Форум сайта python.su
0
Всем доброго времени суток.
Наткнулся я тут на слегка непонятный момент в использовании nonlocal переменных.
Вот такой код:
def f1(): x = 0 def f2(): print(x) x = 1 print(x) f2() f1()
def f1(): x = 0 def f2(): print(x) #x = 1 print(x) f2() def f1(): x = 0 def f2(): #print(x) x = 1 print(x) f2()
Отредактировано shau-kote (Июль 9, 2013 04:25:37)
Офлайн
568
Во втором питоне переменную, определенную в области видимости объемлющей функции можно читать внутри замыкания, но не изменять. В третьем вроде бы появился идентификатор nonlocal.
Для обхода этой неприятности во второй ветке можно использовать такую хитрость
def f1(): f1.x = 10 def f2(): print f1.x f1.x = 1 print f1.x f2() f1()
Офлайн
0
Да, я знаю. У меня у самого Python 3, но я не про nonlocal.
К примеру, С аналогичный код вполне работает - http://codepad.org/eroG1o3S
Первое обращение к x обрабатывается как обращение к глобальной переменной, второй - как к локальной, потому что уже есть локальная переменная x.
Здесь же такая логика почему-то не срабатывает. Интерпретатор считает x локальной переменной ещё до присваивания! Ерунда какая-то получается.
Для сравнения с приведённым выше примером на С - http://codepad.org/4SkOKG2D
Отредактировано shau-kote (Июль 9, 2013 06:11:56)
Офлайн
568
Ну питон - это все таки не С, особенно если вспомнить, что функции в питоне - это объекты.
Как тебе такой код?
x = 0 def f(): x = 31 r = 90 print x c = f.func_code print zip(c.co_consts[1:], c.co_varnames)
Офлайн
0
Хм. То есть уже после выполнения инструкции def мы имеем объект-функцию, которая содержит список всех своих (будущих) локальных переменных, хотя им даже не присвоены значения?..
Офлайн
857
shau-kote
вылетает с UnboundLocalError на первой строке f2(). Причём вылетает при попытке вызвать функцию f1()
>>> def f1(): ... x = 0 ... def f2(): ... print(x) ... x = 1 ... print(x) ... #f2() ... >>> f1() >>>
>>> def f1(): ... x = 0 ... def f2(): ... nonlocal x ... print(x) ... x = 1 ... print(x) ... f2() ... >>> f1() 0 1 >>>
>>> def f1(): ... x = 0 ... def f2(): ... print(globals(), locals()) ... print(x) ... x = 1 ... print(x) ... f2() ... >>> f1() {'__doc__': None, 'f1': <function f1 at 0x7f2eceb3ad40>, '__builtins__': <module 'builtins'>, '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f2eceacb810>, '__name__': '__main__', 'clear': <function clear at 0x7f2eceb3acb0>, '__package__': None, '__cached__': None} {} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in f1 File "<stdin>", line 5, in f2 UnboundLocalError: local variable 'x' referenced before assignment >>>
>>> def f1(): ... x = 0 ... def f2(): ... print globals(), locals() ... print x ... x = 1 ... print x ... f2() ... >>> f1() {'f1': <function f1 at 0x7f6a8871e938>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'clear': <function clear at 0x7f6a8871e8c0>, '__name__': '__main__', '__doc__': None} {} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in f1 File "<stdin>", line 5, in f2 UnboundLocalError: local variable 'x' referenced before assignment >>>
>>> x = 0 >>> ... def f1(): ... def f2(): ... print(globals(), locals()) ... print(x) ... x = 1 ... print(x) ... f2() ... >>> f1() {'__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f70a5d5c810>, 'f1': <function f1 at 0x7f70a5dcbd40>, 'x': 0, '__package__': None, '__builtins__': <module 'builtins'>, '__doc__': None, '__name__': '__main__', 'clear': <function clear at 0x7f70a5dcbcb0>, '__cached__': None} {} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in f1 File "<stdin>", line 5, in f2 UnboundLocalError: local variable 'x' referenced before assignment >>>
>>> x0 = 0 >>> ... def f1(): ... x = 0 ... def f2(): ... print(globals(), locals()) ... print(x0) ... x = 1 ... print(x) ... print(globals(), locals()) ... f2() ... >>> f1() {'__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f70a5d5c810>, 'f1': <function f1 at 0x7f70a5d6f170>, 'x': 0, '__package__': None, '__builtins__': <module 'builtins'>, '__doc__': None, '__name__': '__main__', 'clear': <function clear at 0x7f70a5dcbcb0>, 'x0': 0, '__cached__': None} {} 0 1 {'__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f70a5d5c810>, 'f1': <function f1 at 0x7f70a5d6f170>, 'x': 0, '__package__': None, '__builtins__': <module 'builtins'>, '__doc__': None, '__name__': '__main__', 'clear': <function clear at 0x7f70a5dcbcb0>, 'x0': 0, '__cached__': None} {'x': 1} >>>
>>> def f1(): ... x = 0 ... def f2(): ... print(globals(), locals()) ... print(x) ... #x = 1 ... print(x) ... f2() ... >>> f1() {'f1': <function f1 at 0x7f9a5aafed40>, '__package__': None, 'clear': <function clear at 0x7f9a5aafecb0>, '__doc__': None, '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f9a5aa8f810>, '__builtins__': <module 'builtins'>, '__name__': '__main__', '__cached__': None} {'x': 0} 0 0 >>>
Отредактировано py.user.next (Июль 10, 2013 02:16:55)
Офлайн
47
нашел интересную статью в тему http://blog.amir.rachum.com/post/55024295793/python-common-newbie-mistakes-part-2
Офлайн
0
bismigalis, спасибо за статью.
Вот это кусок:
What really happens here is that the local scope is in fact not completely dynamic. When the def statement is executed, Python statically gathers information regarding the local scope of the function.расставил всё по местам.
Отредактировано shau-kote (Июль 11, 2013 10:16:59)
Офлайн