Ipython: المتغيرات العامة غير محددة في الاستخدام التفاعلي لقشرة ipython المضمنة

تم إنشاؤها على ١٠ مايو ٢٠١٠  ·  39تعليقات  ·  مصدر: ipython/ipython

خطأ Launchpad الأصلي 399627: https://bugs.launchpad.net/ipython/+bug/399627
رواه: h-fangohr (Hans Fangohr).

يمكن تكرار الخطأ على النحو التالي:

  1. ابدأ بايثون ، وابدأ جلسة ipython المضمنة. بعد دليل إيبيثون ، نقوم بذلك
fangohr<strong i="11">@eta</strong>:~$ python
Python 2.4.3 (#1, Jun  8 2009, 14:09:06) 
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from IPython.Shell import IPShellEmbed
>>> ipshell=IPShellEmbed()
>>> ipshell()

خلال جلسة ipython التي بدأت للتو ، لا تظهر المتغيرات العامة في بعض الأحيان. مثالان هما:

مثال 1:

In [1]: a=1

In [2]: def f(x):
   ...:     return a*x
   ...: 

In [3]: f(2)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

/home/fangohr/<ipython console> 

/home/fangohr/<ipython console> in f(x)

NameError: global name 'a' is not defined

المثال 2:

In [4]: b=1

In [5]: (lambda :b)()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

/home/fangohr/<ipython console> 

/home/fangohr/<ipython console> in <lambda>()

NameError: global name 'b' is not defined

لا يوجد خطأ إذا تم وضع "b = 1؛ (lambda: b) ()" في نص برمجي ، ويتم تنفيذ هذا البرنامج النصي باستخدام الأمر ipython "run".

لا يوجد خطأ إذا تم تنفيذ "b = 1؛ (lambda: b) ()" بشكل تفاعلي بعد بدء ipython.

الطريقة الوحيدة التي يظهر بها الخطأ هي إذا تم بدء تشغيل غلاف IPython مضمن من موجه Python ويتم تنفيذ الأوامر بشكل تفاعلي عند المطالبة.

أجد نفس الخطأ عند محاولة ipython-0.9.1 (مع python2.4).

تم الإبلاغ عن الخطأ بواسطة Olivier Klein إلى فريق nmag (http://nmag.soton.ac.uk).

bug

التعليق الأكثر فائدة

كما هو مذكور في https://github.com/inducer/pudb/issues/103 ، فإن الحل المؤقت أثناء استخدام غلاف مضمن هو: globals().update(locals()) (بعد تحديد المتغيرات العالمية المحلية ، فقط).

ال 39 كومينتر

[تعليق LP 1 بواسطة: فرناندو بيريز ، في 25 أبريل 2010 23: 36: 38.673176 + 00: 00]

حسنًا ، يمكنني تأكيد المشكلة (حتى على صندوق السيارة) ، لكنها صعبة. أنا فقط أتأكد الآن من تأكيد هذا الخطأ ، لذا نستمر في تتبعه ، لكنني لست متأكدًا من كيفية إصلاحه.

تكمن المشكلة في أنه في الأصداف المضمنة ، نحاول تحديث مساحة الاسم العالمية لاستخدام النطاق المحيط (هذا هو الهدف من الغلاف المضمن ، لتتمكن من رؤية ما يدور حولك). ولكن هذا يتسبب بعد ذلك في فشل Python في حل مساحة الاسم التفاعلية ipython عند تحديد الأشياء المتداخلة (مثل الوظائف المحلية). راجع طريقة mainloop () الخاصة بالصدفة المضمنة للحصول على التفاصيل.

أحتاج إلى التفكير كثيرًا في كيفية إصلاح هذا ، أي أفكار مرحب بها كثيرًا.

انتهى عند لوحة التشغيل ...

كتب ChiefK قبل 20 ساعة:

أنا أيضا. بالإضافة إلى الوظائف ، يظهر هذا الخطأ أيضًا في تعبيرات المولد.

يبدو أن المكون المكافئ في صندوق الأمتعة هو IPython.frontend.terminal.InteractiveShellEmbed. لكن هذا كسر بطرق أخرى ، ومن الواضح أنه لم يتم اختباره كثيرًا. هل يعرف أحد ما هو مستقبله؟

هل يمكن أن تكون هذه هي نفس المشكلة مثل # 136؟

تم إصلاح هذا الآن:

amirbar[ipython]> python
Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from IPython import embed
>>> embed()
Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12.dev -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: a = 1

In [2]: def f(x):
   ...:     return a*x
   ...: 

In [3]: f(3)
Out[3]: 3

In [4]: b = 1

In [5]: (lambda : b)()
Out[5]: 1

In [6]: 

هل يمكن لأي شخص أن يشرح أكثر قليلاً ما تم إدخاله في إصلاح هذا؟ ما زلت أواجه المشكلة ، ولكن فقط عندما أزيل طبقة واحدة عبر استدعاء طريقة ، وفقط إذا قمت بالتشغيل من برنامج نصي ، وليس بشكل تفاعلي.

python 2.7.2 على OSX 10.6.8 و ipython 0.11 و 0.12 يظهر كلاهما سلوكًا مشابهًا (باستخدام 0.12 لهذا التعليق)

هذه مشكلة في مشروعنا الذي يتميز (بشكل بارز) بقشرة IPython مضمنة.

testembed.py

from IPython import embed

def hi():
    embed()

if __name__ == '__main__':
    #embed()
    hi()

قم بتشغيل هذا في سطر الأوامر باستخدام python testembed.py وانظر هذه الجلسة:

Python 2.7.2 (default, Aug 29 2011, 12:33:18) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import time

In [2]: def tim():
   ...:     print time.time()
   ...:     

In [3]: tim()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
[snip] in <module>()
----> 1 tim()

[snip] in tim()
      1 def tim():
----> 2     print time.time()
      3 

NameError: global name 'time' is not defined

In [4]: 

ومع ذلك ، قم بالتعليق على المكالمة إلى hi() واستبدلها بـ embed() call:

Python 2.7.2 (default, Aug 29 2011, 12:33:18) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import time

In [2]: def tim():
    print time.time()
   ...:     

In [3]: tim()
1328639444.29

In [4]: 

بعد البحث ، أعتقد أن الأمر يتعلق بالمعامل stack_depth المستخدم هنا وهذه الكتلة: https://github.com/ipython/ipython/blob/master/IPython/frontend/terminal/embed.py # L185

أفكار؟

هذا معقد إلى حد ما ، لكنني أعتقد أن هذا قيد في بايثون نفسها.

في حالة الفشل التي تظهرها ، لم يتم وضع time فعليًا في مساحة الاسم العالمية: نظرًا لأنك استدعيت embed داخل الدالة hi ، فإن المتغيرات الجديدة التي تنشئها بشكل تفاعلي تكون محلية لذلك وظيفة. من الناحية المثالية ، يجب أن يعمل tim() كإغلاق ، مع إغلاق الإشارة إلى وحدة الوقت. ومع ذلك ، يبدو أن عمليات الإغلاق تعمل فقط عندما يتم تجميع وظيفة الحاوية دفعة واحدة. بقدر ما أستطيع أن أقول ، لا توجد طريقة لتحديد الإغلاق ديناميكيًا. فشل هذا المثال البسيط:

def outer():
    import time
    exec("def inner(): return time.time()")
    return inner

outer()()

ربما يكون هذا بسبب إضافة النطاقات المتداخلة إلى Python في وقت متأخر نسبيًا (كانت استيرادًا مستقبليًا في 2.1 ، ودائمًا في 2.2).

حسنًا ، أعتقد أنني أفهم. يبدو أننا لا نستطيع فعل أي شيء حيال هذا بعد ذلك ، بخلاف تفريغ ما سأكتبه بشكل تفاعلي إلى ملف ثم قراءة هذا الملف مرة أخرى. ربما يكون معقدًا جدًا لما نريد أن نكون قادرين على القيام به بشكل تفاعلي.

شكرا ، راجع للشغل.

آسف للاستمرار في العزف هنا ، لكنه يجعل الجلسات التفاعلية تشعر بالضيق الشديد:

الثعبان العادي:

>>> d={'one':1, 'two':2}
>>> getkeys=lambda: d.keys()
>>> getkeys()
['two', 'one']

منتظم IPython:

In [1]: d={'one':1, 'two':2}

In [2]: getkeys=lambda: d.keys()

In [3]: getkeys()
Out[3]: ['two', 'one']

IPython مضمن:

>>> from IPython import embed
>>> embed()
Python 2.7.2 (default, Aug 29 2011, 12:33:18) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12.dev -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: d={'one':1, 'two':2}

In [2]: getkeys=lambda: d.keys()

In [3]: getkeys()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/asadeveloper/Documents/Dev/code/pyon/bin/python in <module>()
----> 1 getkeys()

/Users/asadeveloper/Documents/Dev/code/pyon/bin/python in <lambda>()
----> 1 getkeys=lambda: d.keys()

NameError: global name 'd' is not defined

أعتقد أنه لا يوجد الكثير الذي يمكن القيام به ، لكنني لا أفهم لماذا يمكننا إنشاء إغلاق ديناميكي في python / ipython العادي ولكن ليس الإصدار المدمج.

من خلال شذوذ تحديد نطاق بايثون ، في Python / IPython القياسي ، لا نقوم في الواقع بإنشاء إغلاق. d متغير عام ، وتعمل قواعد الوصول إليه بشكل مختلف عن عمليات الإغلاق. تحتفظ كل دالة بمرجع إلى مساحة الاسم العالمية حيث تم تعريفها ( getkeys.func_globals ) ، حتى تتمكن من الوصول إلى أي متغيرات محددة هناك.

في المقابل ، عندما تقوم بإغلاق ، فإن Python ترفق مراجع لكل متغير أغلقت عليه ، على النحو الذي يحدده المترجم - لكن هذا لا يعمل إلا عندما يتم تجميع الوظائف الداخلية والخارجية في نفس الوقت. تبدو هكذا:

In [8]: def outer():
    a = 1
    def inner():
        return a
    return inner
   ...: 

In [9]: f = outer()

In [10]: f
Out[10]: <function __main__.inner>

In [11]: f.func_closure
Out[11]: (<cell at 0x9f5e344: int object at 0x9a830b0>,)

من المحتمل أن يتم ذلك لحفظ الذاكرة - إذا كان الإغلاق يحمل إشارة إلى النطاق المحلي حيث تم تحديده ، فلا يمكن تحرير أي من المتغيرات من هذا النطاق أثناء تفعيل الإغلاق.

أنا أستخدم Python 2.7.2 و IPython 0.12.1 على OSX 10.7.3 ولا تزال هذه المشكلة قائمة. عندما أقوم بتشغيل ./manage.py shell من Django الذي يستدعي IPython.embed() ، تحدث المشكلة. ومع ذلك ، لا توجد مشكلة في استدعاء embed() يدويًا في غلاف Python أو من ملف نصي بسيط.

ليس هناك الكثير الذي يمكننا القيام به بشكل مباشر حيال ذلك ، ولكن من المحتمل أن نشجع الجهات الخارجية على الابتعاد عن embed للاستخدامات غير التافهة.

takluyver هل تقصد أنه من الأفضل استخدام ipython مباشرة في هذه الحالة؟

من الممكن أن يبدأ Django في IPython بطريقة لا تسبب هذه المشكلة ، لكن هذه ليست الطريقة التي نسهلها حاليًا. تحدث المشكلة عندما يبدأ IPython بمساحات أسماء محلية وعالمية منفصلة. لا يوجد سبب يجعل Django يتطلب مساحات أسماء محلية وعالمية منفصلة ، ولكن هذا ما يعنيه استدعاء embed() داخل الوظيفة.

كمرجع ، هذا هو الرمز في Django:
https://code.djangoproject.com/browser/django/trunk/django/core/management/commands/shell.py

takluyver هذا منطقي ، شكرا! سأفتح تذكرة Django لهذا.

takluyver ، الآن بعد أن دمجنا embed_kernel بحيث أصبحت جميع القطع الرئيسية في مكانها الصحيح ، هل تريد معالجة القليل من تنظيف هذا الأمر لتسهيل استخدامات أكثر دقة؟

سألقي نظرة على الواجهة الأكثر منطقية.

ما زلت أواجه مشكلة مع هذه المشكلة. لقد حاولت تضييق سبب ذلك بالضبط ، وأفضل ما يمكنني تحديده هو أنه يحدث فقط على Ubuntu 12.04. لقد جربت جميع إصدارات الإصدار الأخيرة على خوادم أخرى ، وهي تعمل بشكل جيد. ولكن في أي وقت أقوم بتعريف دالة في ipython أو استخدم٪ cpaste للصق دالة من ملف آخر ، فإن الجزء الداخلي من هذه الوظيفة ليس له حق الوصول إلى النطاق العام. يجعل من المستحيل بشكل أساسي القيام بأي شيء مفيد من حيث وظائف الكتابة أثناء التنقل.

ما زلت أواجه هذه المشكلة مع IPython 0.13 عندما يتم استدعاؤها من أدوات أخرى (مثل أمر debugsqlshell من Django). إنه أمر محبط للغاية أن شيئًا أساسيًا مثل تعريف الوظيفة معطل تمامًا.

أعتقد أن embed () هي الواجهة الخاطئة لمن يستخدمونها. embed () هو
المقصود أكثر لفحص حالة البرنامج قيد التشغيل ، لذلك يستخدم
فصل مساحات الأسماء المحلية والعالمية. للتغلب على هذه المشكلة ، ipython
يجب أن تبدأ بواجهة واحدة. آسف ، لم يكن لدي الوقت
اكتشف أفضل طريقة للقيام بذلك.

ليس فقط أوبونتو. يظهر ديبيان ويزي أيضًا ذلك.

لمعلوماتك ، تذكرة Djangoliokm التي تم إنشاؤها أعلاه هي https://code.djangoproject.com/ticket/18204 ، والتي تشير الآن إلى https://code.djangoproject.com/ticket/17078 ، والتي يبدو أنها قد تم إصلاحها في صندوق الأمتعة . يجب أن تهبط في 1.5.

أواجه نفس المشكلة على Ubuntu مع Ipython 0.13.2
screenshot from 2013-08-07 18 13 33

bkvirendra الذي تم إصلاحه في django 1.6

لكن 1.6 ليست مستقرة حتى الآن!

لكن 1.6 ليست مستقرة حتى الآن!

البرامج ليست مستقرة دائمًا ، وربما لا تزال هناك أخطاء بين الإصدارات. لكن لا يوجد شيء يجب إصلاحه في IPython. حتى لو فعلنا شيئًا هنا ، فلن يكون الإصلاح في IPython ثابتًا قبل إصداره أيضًا ...

لا تزال المشكلة قائمة في ipython == 4.2.0. من المثير للاهتمام أنه لا توجد مشكلة تحت النوافذ ولكن مع المتغيرات العالمية أوبونتو لم يتم التعرف عليها.

حالة الاستخدام:

from ipywidgets import interact, FloatSlider, IntSlider,RadioButtons, Dropdown

@interact(sv1 = radio_1, Scenario = drop_1, sv2 = slider_2)
def update_map(sv1,sv2, Scenario):

تبقى المشكلة. IPython 3.1.0 ، Debian Whezzy.

إذا كنت أتذكر بشكل صحيح ، فقد تم إصلاح هذا لفترة قصيرة ، ويبدو أنه قد أعيد تقديمه (تم إعادة إنتاجه باستخدام IPython 5.1.0 على macOS هنا: https://git.io/vPDrJ).

(تحرير: ربما أخطأت في تذكر الإصلاح. من المحتمل أنني رميت كل ما أحتاجه في ملف بدء التشغيل بدلاً من استخدام التضمين)

فقط في حالة مساعدة هذا أي شخص كنت أستخدم هذا الجزء من التعليمات البرمجية كحل بديل

    def fix_embed_globals(N=0):
        # Get the parent frame
        import inspect
        frame_level0 = inspect.currentframe()
        frame_cur = frame_level0
        N = 2  # I may have this value off by one. I rewrote this function to use only standard calls
        strict = False
        for _ix in range(N + 1):
            frame_next = frame_cur.f_back
            if frame_next is None:
                if strict:
                    raise AssertionError('Frame level %r is root' % _ix)
                else:
                    break
            frame_cur = frame_next
        parent_frame = frame_cur
        # Add locals to parent globals
        parent_frame.f_locals.update(parent_frame.f_globals)
        parent_frame.f_globals['_didfixipyglobals'] = True

أنا فقط أسمي هذه الوظيفة كلما تلقيت خطأ في الاسم. يضع جميع السكان المحليين في إطارك الحالي في القاموس العالمي. إنه اختراق ولكنه يعمل في معظم الظروف.

كما هو مذكور في https://github.com/inducer/pudb/issues/103 ، فإن الحل المؤقت أثناء استخدام غلاف مضمن هو: globals().update(locals()) (بعد تحديد المتغيرات العالمية المحلية ، فقط).

حسنًا ، هل يمكن تغيير معلم هذا الخطأ إلى أحد الإصدارات التالية؟

منجز.

هل سيتم إصلاح هذا يوما ما؟

AFAIK ، تعليقاتي من قبل بضع سنوات تقف:

  1. أعتقد أننا مقيدون بطريقة عمل بايثون نفسها. لا تعمل عمليات الإغلاق والتقييم الديناميكي جيدًا معًا ، ولا يستطيع IPython إصلاحها. لقد توصل الأشخاص إلى حلول بديلة لنقل المتغيرات المحلية إلى مساحة اسم عالمية ، ولكن هذه اختراقات يمكن أن تسبب مشكلات أخرى ، لأنها تعدل مساحة الاسم العالمية. لا أخطط لوضع مثل هذه الحلول في IPython ؛ أفضل ترك مشكلة في شيء لا نفعله بدلاً من تقديم واحدة بمحاولة أن نكون ذكيين للغاية.

  2. في العديد من الأماكن التي اعتقد الناس أنهم يريدون embed() ، يجب عليهم استخدام start_ipython() بدلاً من ذلك وتجنب هذا النوع من المشكلات.

أنا لا أفهم ، وهذا يجعلني غاضبًا.

آسف ، لقد شعرت بالإحباط لأن الأشياء التي ستنجح إذا كتبتها في ملف .py فارغ لا تعمل هنا

لكن إعادة قراءة السجل ، يبدو أن هذه مشكلة مع Django manage.py shell وجه التحديد ، 90٪ من الوقت الذي أكون فيه في ipython أفعل ذلك ولكن من السهل أن تنسى هذا هو الحال

بشكل محرج أنا أعمل كثيرًا في إصدار قديم من Django (1.4)

وفقًا للتعليق السابق ، فإن الإصدارات الأحدث من Django shell تستخدم ipython بشكل مختلف وقد لا تعاني من المشكلة؟ على سبيل المثال https://code.djangoproject.com/ticket/17078

نعتذر عن سوء التفاهم

نعم ، أعتقد أنه تم إصلاحه لـ Django 1.6. إذا كنت لا تستطيع الترقية حقًا ، فقد ترغب في تطبيق الإصلاح يدويًا. يبدو أن هذا هو: https://github.com/django/django/commit/3570ff734e93f493e023b912c9a97101f605f7f5

لقد وجدت حلاً اليوم تم نشره في # 10695 . يتم عرض معالجة أبسط للحالة التي لا يتم فيها تضمين IPython داخل وظيفة في هذا الخيط . أنا لست خبيرًا ، لذا يُرجى المساعدة في التحقق من الصلاحية.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

sataliulan picture sataliulan  ·  4تعليقات

ederag picture ederag  ·  3تعليقات

ipython picture ipython  ·  3تعليقات

ericdill picture ericdill  ·  3تعليقات

ghost picture ghost  ·  4تعليقات