Сообщение от Zeroglif
|
тем больше слоняюсь к мысли, что условия не нужны
|
Возможно. Возможно, в JS оно и так. Хотя, для полного определения, всё же, наверное, лучше две теории упоминать.
Но, сегодня более глубоко посмотрел, как это дело обстоит в Python'е (да-да, опять Питон
). Так вот. Там так же работает механизм цепи скопов (т.е. из вложенных функций мы можем достучаться до всех вышестоящих переменных/объектов, включая глобальный скоп). Однако, начиная с версии Python'a 3.0, у функций есть интересное свойство -
__closure__, которое:
Цитата:
|
None or a tuple of cells that contain bindings for the function’s free variables.
|
Можно почитать здесь -
http://docs.python.org/3.0/reference/datamodel.html, конкретно раздел "Callable types".
Это свойство, как было сказано, хранит кортеж (tuple, неизменяемый массив) свободных переменных функции. Т.е. это тот самый [[scope]] из JS, который записался в функцию при её создании, только здесь мы имеем к нему доступ явно. Но! Самое интересное здесь то, что
глобальные переменные туда не входят! Здесь, если функция глобальная - у неё, считается, нет свободных
лексических локальных переменных (и в этом случае, __closure__ == None):
a = 10
# глобальная функция
def x():
print(a)
x() # 10, работает, но:
x.__closure__ # None
А теперь с вложенными функциями:
a = 10
def x():
b = 20
def y(): # первая вложенная
c = 30
def z(): # вторая вложенная
print(a, b, c)
return z # возврат из y
return y # возврат из x
# проверка
dy = x() # вернувшаяся функция "y"
dz = dy() # вернувшаяся функция "z", можно было сразу - x()()
dz() # 10, 20, 30
# замыкание внешней функции "x"
x.__closure__ # None
# замыкание внутренней функции "y" (dy)
dy.__closure__ # (<cell at 0x0143AE70: int object at 0x1E1E5678>,) - кортеж из одного элемента
dy.__closure__[0] # <cell at 0x0143AE70: int object at 0x1E1E5678> - этот самый элемент, объект cell
dy.__closure__[0].cell_contents # а вот она наша 20!
dy.__closure__[1] # ошибка! нет элемента с индексом 1, только одна свободная переменная, глобальная "а" сюда не входит
# замыкание внутренней функции "z" (dz)
dz.__closure__ # два объекта, как и ожидалось - (<cell at 0x0143E970: int object at 0x1E1E5718>, <cell at 0x0143AE70: int object at 0x1E1E5678>)
dz.__closure__[0].cell_contents # 30
dz.__closure__[1].cell_contents # 20
dz.__closure__[2].cell_contents # ошибка, только две свободные переменные
Т.е. здесь, обособление лексических переменных от глобальных представлено явно. И именно лексические переменные попали в замыкание.
P.S.:>
Zeroglif, скачай, поставь интерпретатор Python'a, тоже, как и JS, интересно.
P.S.[2]:> сейчас ещё и Ruby посмотрел - там тоже есть явное разделение на глобальные переменные (префикс - $: $a, $b и т.д.), и локальные - без префиксов. Так вот глобальные переменные могут использоваться в методах (def'ы), в то время как
локальные для глобального контекста - нет:
a = 10
def x
puts a
end
x # ошибка, переменная "а" не определена
$b = 10
def y
puts $b
end
y # 10, все Ок
В свою очередь замыкания в Ruby, которые создаются через block'и, lambda'ы и Proc'ы, запоминают эти лексические переменные:
a = 10
x = lambda {
puts a
}
x.call # 10
В общем, сколько идей, столько и реализаций