Оригинальная ошибка Launchpad 399627: https://bugs.launchpad.net/ipython/+bug/399627
Сообщает: h-fangohr (Ханс Фангор).
Ошибка может быть воспроизведена следующим образом:
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).
Об ошибке сообщил Оливье Кляйн команде nmag (http://nmag.soton.ac.uk).
[LP, комментарий 1, автор: Фернандо Перес, 25 апреля 2010 г., 23:36: 38.673176 + 00:00]
Хорошо, я могу подтвердить проблему (даже на стволе), но это сложно. Я просто пока убеждаюсь, что эта ошибка подтверждена, поэтому мы продолжаем отслеживать ее, но я не знаю, как ее исправить.
Проблема в том, что во встроенных оболочках мы пытаемся обновить глобальное пространство имен для использования окружающей области (это точка встроенной оболочки, чтобы иметь возможность видеть, что вас окружает). Но это затем приводит к тому, что python не может разрешить интерактивное пространство имен ipython, когда определены вложенные вещи (например, локальные функции). Подробнее см. Метод встроенной оболочки mainloop ().
Мне нужно больше думать о том, как это исправить, любые идеи приветствуются.
На стартовой площадке ...
ChairmanK написал 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()
:
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
Мысли?
Это несколько сложно, но я считаю, что это ограничение самого Python.
В указанном вами неудачном случае 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, в стандартном 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
нужно запускать с помощью единого интерфейса. Извини, у меня не было времени
выяснить, как лучше всего это сделать.
Не только убунту. Debian wheezy также показывает это.
К вашему сведению, созданный выше билет Django @liokm - это https://code.djangoproject.com/ticket/18204 , который теперь указывает на https://code.djangoproject.com/ticket/17078 , который, похоже, был исправлен в багажнике. . Он должен приземлиться через 1.5.
У меня такая же проблема с Ubuntu с Ipython 0.13.2.
@bkvirendra , исправленный в django 1.6
Но 1.6 еще даже не стабильна!
Но 1.6 еще даже не стабильна!
Программное обеспечение не всегда стабильно, и между выпусками все еще могут быть ошибки. Но в IPython нет ничего, что нужно было бы исправить. Даже если мы что-то сделаем здесь, исправления не будет в стабильной версии IPython до его выпуска ...
Проблема все еще сохраняется в ipython == 4.2.0. Что интересно, под окнами это не проблема, но вместе с глобальными переменными ubuntu они не распознаются.
Пример использования:
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, мои комментарии, сделанные несколько лет назад:
Я считаю, что мы ограничены тем, как работает сам Python. Замыкания и динамическая оценка несовместимы вместе, и IPython не может это исправить. Люди нашли обходные пути для перемещения локальных переменных в глобальное пространство имен, но это хаки, которые могут вызвать другие проблемы, поскольку они изменяют глобальное пространство имен. Я не планирую добавлять такие обходные пути в IPython; Я лучше оставлю проблему с тем, чем мы не занимаемся, чем представлю ее, пытаясь быть слишком умными.
Во многих местах, где люди думали, что им нужно embed()
, им следует использовать вместо них start_ipython()
и избегать подобных проблем.
Я не понимаю, и это меня злит.
извините, я был разочарован тем, что вещи, которые будут работать, если вы напечатаете их в пустой файл .py, здесь не работали
но перечитывая историю, кажется, что это проблема с manage.py shell
Django в частности, 90% времени я нахожусь в ipython, я делаю это, но легко забыть, что это так
стыдно, что я много работаю над устаревшей версией Django (1.4)
согласно предыдущему комментарию, более новые версии оболочки Django используют ipython по-другому и могут не иметь проблемы? например https://code.djangoproject.com/ticket/17078
извинения за недоразумение
Ага, я думаю, что это было исправлено для Django 1.6. Если вы действительно не можете выполнить обновление, возможно, вы захотите применить исправление вручную. Похоже, вот оно что: https://github.com/django/django/commit/3570ff734e93f493e023b912c9a97101f605f7f5
Сегодня я нашел обходной путь, опубликованный на # 10695 . В этом потоке показано более простое решение для случая, когда IPython не встроен в функцию. Я не эксперт, поэтому, пожалуйста, помогите проверить правильность.
Самый полезный комментарий
Как указано на https://github.com/inducer/pudb/issues/103 , временный обходной путь при использовании встроенной оболочки:
globals().update(locals())
(только после определения локальных глобальных переменных).