/PROG/ Python scopes
Aug. 27th, 2006 11:30 amЕсли Питон вымрет, то самым толстым гвоздём в крышку гроба будет не система отступов, к которой привыкнуть - дело пары часов, не динамическая типизация и не отсутствие ограничения видимости при инкапсуляции, а клинически неестественная схема видимости переменных.
Простейший пример:
Оно отвечает:
А теперь если убрать назначение p всё будет работать:
Но если мы после 'print p' добавим инкремент - всё снова сломается, и не выполнится даже print:
будет ошибка дословно повторяющая первый случай, 'print p' не сработает.
Смотрим как это сказано в описании языка (пункт 4.1, 'Naming and binding'):
Each occurrence of a name in the program text refers to the binding of that name established in the innermost function block containing the use.
Ну да, если внимательно вчитаться (и с поправкой далее сказанной очень туманно) что function block это и уровень модуля - да, поведение соответствует описанию. Только вопрос - из какой такой логики переменные можно читать (а заодно вызывать в них методы, и вообще вытворять всё что угодно), но нельзя делать только одно - присвоение?
Как для меня вывод однозначен - результат бессмысленной экономии на (в терминах перла) my и local.
global в использующем блоке это лечит (thx2 ormuz, я как-то пропустил из-за чрезмерной лаконичности документации). Но только по отношению к глобальным переменным (тем что в globals). И логика этого действия противоположна тому что принимается в более нормальных средствах - когда надо явно объявить переменную какая она (local, global, из внешнего блока) при жёстком контроле. Проверки компилятора и pychecker'а слабоваты.
Более скрытая вариация на ту же тему:
Запустив получаем:
Опять g1 оказалось локальным только потому что ему есть хотя бы одно присвоение. 'global g1' не помогло.
UPDATED (12:56) UPDATED(28.08 18:16)
Простейший пример:
def main():
p += 1
if __name__ == '__main__':
p = 0
main()
Оно отвечает:
Traceback (most recent call last):
File "1.py", line 6, in ?
main()
File "1.py", line 3, in main
p += 1
UnboundLocalError: local variable 'p' referenced before assignment
А теперь если убрать назначение p всё будет работать:
def main():
print p
if __name__ == '__main__':
p = 0
main()
Но если мы после 'print p' добавим инкремент - всё снова сломается, и не выполнится даже print:
def main():
print p
p += 1
if __name__ == '__main__':
p = 0
main()
будет ошибка дословно повторяющая первый случай, 'print p' не сработает.
Смотрим как это сказано в описании языка (пункт 4.1, 'Naming and binding'):
Each occurrence of a name in the program text refers to the binding of that name established in the innermost function block containing the use.
Ну да, если внимательно вчитаться (и с поправкой далее сказанной очень туманно) что function block это и уровень модуля - да, поведение соответствует описанию. Только вопрос - из какой такой логики переменные можно читать (а заодно вызывать в них методы, и вообще вытворять всё что угодно), но нельзя делать только одно - присвоение?
Как для меня вывод однозначен - результат бессмысленной экономии на (в терминах перла) my и local.
global в использующем блоке это лечит (thx2 ormuz, я как-то пропустил из-за чрезмерной лаконичности документации). Но только по отношению к глобальным переменным (тем что в globals). И логика этого действия противоположна тому что принимается в более нормальных средствах - когда надо явно объявить переменную какая она (local, global, из внешнего блока) при жёстком контроле. Проверки компилятора и pychecker'а слабоваты.
Более скрытая вариация на ту же тему:
$ tail +1 main.py A.py
==> main.py <==
#!/usr/bin/env python
import A
from A import g1
if __name__ == '__main__':
g1 = {}
print id(g1), A.f1()
A.g1 = g1
print id(g1), A.f1()
==> A.py <==
## module A
g1 = None
def f1():
return id(g1)
Запустив получаем:
136034476 135227424
136034476 136034476
Опять g1 оказалось локальным только потому что ему есть хотя бы одно присвоение. 'global g1' не помогло.
UPDATED (12:56) UPDATED(28.08 18:16)
no subject
Date: 2006-08-27 09:49 am (UTC)no subject
Date: 2006-08-28 10:21 am (UTC)global_f = f
def jump():
f = ["jump"]
upvar_f = f
def kick():
f = ["kick"]
upvar_f.extend(f)
kick()
global_f.extend(f)
jump()
print f
не думаю что лучше было бы что-то вроде ../f = f + ../../f * /f
название - самая сложная вещь, но нужная.. :)
no subject
Date: 2006-08-28 10:22 am (UTC)f=["stand"] global_f = f def jump(): f = ["jump"] upvar_f = f def kick(): f = ["kick"] upvar_f.extend(f) kick() global_f.extend(f) jump() print fno subject
Date: 2006-08-28 03:19 pm (UTC)no subject
Date: 2006-08-28 03:21 pm (UTC)