Это больше любопытство, чем что-либо, но я только заметил следующее. Если я определяю самореферентную лямбду, я могу сделать это легко:
>>> f = lambda: f
>>> f() is f
True
Но если я определяю самореференционный список, я должен сделать это более чем в одном утверждении:
>>> a = [a]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> a = []
>>> a.append(a)
>>> a[0] is a
True
>>> a
[[...]]
Я также заметил, что это не ограничивается списками, но похоже, что любое другое выражение, отличное от лямбда, не может ссылаться на переменную слева от назначения. Например, если у вас есть циклический связанный список с одним node, вы не можете просто пойти:
>>> class Node(object):
... def __init__(self, next_node):
... self.next = next_node
...
>>> n = Node(n)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'n' is not defined
Вместо этого вы должны сделать это в двух утверждениях:
>>> n = Node(None)
>>> n.next = n
>>> n is n.next
True
Кто-нибудь знает, что такое философия, лежащая в основе этой разницы? Я понимаю, что рекурсивная лямбда используется гораздо чаще, и, следовательно, поддержка самореференции важна для лямбда, но почему бы не разрешить ее для какого-либо назначения?
РЕДАКТИРОВАТЬ: ответы ниже разъясняют это довольно хорошо. Причина в том, что переменные в lambdas на Python оцениваются каждый раз, когда вызывается лямбда, а не когда она определена. В этом смысле они точно такие же, как функции, определенные с помощью def
. Я написал следующий бит кода, чтобы поэкспериментировать с тем, как это работает, как с функциями lambdas, так и с def
, если это может помочь прояснить его для всех.
>>> f = lambda: f
>>> f() is f
True
>>> g = f
>>> f = "something else"
>>> g()
'something else'
>>> f = "hello"
>>> g()
'hello'
>>> f = g
>>> g() is f
True
>>> def f():
... print(f)
...
>>> f()
<function f at 0x10d125560>
>>> g = f
>>> g()
<function f at 0x10d125560>
>>> f = "test"
>>> g()
test
>>> f = "something else"
>>> g()
something else