Самое важное ограничение, в настоящее время, то, что Вы не можете присвоить переменной внешнего объема. Другими словами, закрытия только для чтения:
>>> def outer(x):
... def inner_reads():
... # Will return outer's 'x'.
... return x
... def inner_writes(y):
... # Will assign to a local 'x', not the outer 'x'
... x = y
... def inner_error(y):
... # Will produce an error: 'x' is local because of the assignment,
... # but we use it before it is assigned to.
... tmp = x
... x = y
... return tmp
... return inner_reads, inner_writes, inner_error
...
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
5
>>> inner_error(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in inner_error
UnboundLocalError: local variable 'x' referenced before assignment
имя А, которому присваивают в локальном объеме (функция) всегда локально, если не объявлено иначе. В то время как существует 'глобальное' объявление для объявления переменной, глобальной, даже когда ему присваивают, нет такого объявления для вложенных переменных - еще. В Python 3.0, существует (будет), 'нелокальное' объявление, которое делает просто это.
можно работать вокруг этого ограничения тем временем при помощи изменяемого контейнерного типа:
>>> def outer(x):
... x = [x]
... def inner_reads():
... # Will return outer's x's first (and only) element.
... return x[0]
... def inner_writes(y):
... # Will look up outer's x, then mutate it.
... x[0] = y
... def inner_error(y):
... # Will now work, because 'x' is not assigned to, just referenced.
... tmp = x[0]
... x[0] = y
... return tmp
... return inner_reads, inner_writes, inner_error
...
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
10
>>> inner_error(15)
10
>>> inner_reads()
15
Единственная трудность, с которой я видел, что люди встречаются с Python в особенности, состоит в том, когда они пытаются смешать нефункциональные функции как переменное переназначение с закрытиями и удивлены, когда это не работает:
def outer ():
x = 1
def inner ():
print x
x = 2
return inner
outer () ()
Обычно просто указания, что функция имеет свои собственные локальные переменные, достаточно для удерживания такой глупости.
Зафиксированный в Python 3 через nonlocal
оператор:
nonlocal
оператор заставляет перечисленные идентификаторы относиться к ранее связанным переменным в самом близком объеме включения, исключая globals. Это важно, потому что поведение по умолчанию для привязки должно искать локальное пространство имен сначала. Оператор позволяет инкапсулировавшему коду снова переплетать переменные за пределами локального объема помимо глобального (модуль) объем.
Миллисемья @John
def outer():
x = 1 # local to `outer()`
def inner():
x = 2 # local to `inner()`
print(x)
x = 3
return x
def inner2():
nonlocal x
print(x) # local to `outer()`
x = 4 # change `x`, it is not local to `inner2()`
return x
x = 5 # local to `outer()`
return (inner, inner2)
for inner in outer():
print(inner())
# -> 2 3 5 4
комментарий для @Kevin Мало является ответом для включения примера кода
nonlocal
, не решает полностью эту проблему на python3.0:
x = 0 # global x
def outer():
x = 1 # local to `outer`
def inner():
global x
x = 2 # change global
print(x)
x = 3 # change global
return x
def inner2():
## nonlocal x # can't use `nonlocal` here
print(x) # prints global
## x = 4 # can't change `x` here
return x
x = 5
return (inner, inner2)
for inner in outer():
print(inner())
# -> 2 3 3 3
, С другой стороны:
x = 0
def outer():
x = 1 # local to `outer`
def inner():
## global x
x = 2
print(x) # local to `inner`
x = 3
return x
def inner2():
nonlocal x
print(x)
x = 4 # local to `outer`
return x
x = 5
return (inner, inner2)
for inner in outer():
print(inner())
# -> 2 3 5 4
это работает над python3.1-3.3
Лучшим обходным путем до версии 3.0 является включение переменной в качестве параметра по умолчанию в прилагаемое определение функции:
def f() x = 5 def g(y, z, x=x): x = x + 1