Есть ли Pythonic способ закрыть переменную цикла? - PullRequest
20 голосов
/ 20 января 2012

Я только что наткнулся на Эрика Липперта, закрывающего переменную цикла, считавшегося вредным через SO, и после экспериментов понял, что такая же проблема существует (и еще труднее обойти) в Python.*

>>> 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-пути вызовов вложенных функций, чтобы создать действительно новые переменные?

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

1 Ответ

24 голосов
/ 20 января 2012

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

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

Это работает, потому что оно определяет r в локальной области действия foo и привязывает к нему значение по умолчанию во время определения 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 и привязывает к нему значение при вызове make_foo(r). Позже, когда вызывается f(), ищется r с использованием правила LEGB . Хотя r не найдено в локальной области действия foo, оно находится в прилагаемой области действия make_foo.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...