2012-01-20 2 views
18

Я просто столкнулся с Closing over the loop variable considered harmful Эриком Липпертом через SO, и после экспериментов понял, что такая же проблема существует (и еще сложнее обойти) в Python.Есть ли у Pythonic способ закрыть переменную цикла?

>>> l = [] 
>>> for r in range(10): 
... def foo(): 
...  return r 
... l.append(foo) 
... 
>>> for f in l: 
... f() 
... 
9 
9 
9 
# etc 

и, стандарт C# обходной путь не работает (я предполагаю, что из-за характера ссылок на Python)

>>> l = [] 
>>> for r in range(10): 
... r2 = r 
... def foo(): 
...  return r2 
... l.append(foo) 
... 
>>> for f in l: 
... f() 
... 
9 
9 
9 
# etc 

Я признаю, что это не большая проблема в Python с его основное внимание уделяется структурам, не связанным с закрытием, но мне любопытно, есть ли очевидный Pythonic способ справиться с этим, или нам нужно идти по пути JS вызовов вложенных функций для создания фактически новых vars?

>>> l = [] 
>>> for r in range(10): 
...  l.append((lambda x: lambda: x)(r)) 
... 
>>> for f in l: 
...  f() 
... 
0 
1 
2 
# etc 

ответ

23

Один из способов заключается в использовании параметра со значением по умолчанию:

l = [] 
for r in range(10): 
    def foo(r = r): 
     return r 
    l.append(foo) 

for f in l: 
    print(f()) 

дающий

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 

Это работает, потому что она определяет в локальной области foo «ы в r, и связывает значение по умолчанию для него в момент времени foo.


Другой способ заключается в использовании функции завод:

l = [] 
for r in range(10): 
    def make_foo(r): 
     def foo(): 
      return r 
     return foo 
    l.append(make_foo(r)) 

for f in l: 
    print(f()) 

Это работает, потому что она определяет r в локальной области make_foo «s, и связывает значение к нему, когда make_foo(r) называется. Позже, когда вызывается f(), r просматривается с использованием LEGB rule. Хотя r не найден в местной области foo, он находится в прилагаемой области make_foo.

+1

О, мне нравится этот трюк по умолчанию. Эта фабрика функций семантически похожа на двойную лямбда-вещь в конце моей. Тем не менее, фабрики лямбда - это проницательность. – quodlibetor

Смежные вопросы