`x = 42; 怎么样? x = lambda: x` 解析了吗?

How is `x = 42; x = lambda: x` parsed?

令我惊讶的是这个断言失败了:

x = 42
x = lambda: x
assert x() == 42

看来x最终递归引用了自己,所以x()x()()等都是函数

用于解析的规则是什么,记录在何处?

顺便说一句(不是意外地给出了上面),x 的原始值在 lambda 定义之后没有留下任何引用:

class X:
  def __del__(self): print('deleting')

x = X()
x = lambda: x  # 'deleting' is printed here

第一个作业无关; lambda 正文中的 xbound late:

x = lambda: x # no need for a prior assignment
x = lambda: y # notice: no NameError occurs, *until it is called*

这与creating lambdas in a loop is tricky, and is also used to make trees with the standard library defaultdict:

的原因相同
tree = lambda: defaultdict(tree)
t = tree()
t['foo']['bar']['baz'] = 'look ma, no intermediate steps'

lambda 是一个匿名函数对象。 Python 将等式右侧的所有内容完全解析为单个匿名对象,然后解析左侧的所有内容以进行赋值。

x = lambda: x

首先将 lambda: x 编译成一个函数对象,该函数对象 returns 调用时 x 中的任何内容。然后它用这个函数对象重新绑定 x,删除之前恰好存在的任何对象。

现在 x 是 returns x 中的任何函数...这是 returns x 中的任何函数,等等...所以你可以写 x()()()()()() 任意多次,并且仍然得到原始的 lambda:x 函数对象。

Python 函数有一个本地命名空间,但只有在函数中分配的变量驻留在那里。由于 x 未在 lambda 中分配,因此在包含范围内解析 - 即模块级别“x”。一段相同的代码是

def x():
    return x

对比一下

def x():
    x = 1
    return x

现在,参数x是局部变量,与全局x无关。

变量x由第一次赋值创建,并在第二次赋值时反弹。

由于在调用 lambda 之前不会计算 lambda 中的 x,因此调用它将计算为最近分配的值。

请注意,这不是动态作用域 - 如果它是动态的,则以下内容将打印“99”,但它会打印“

x = 42
x = lambda: x

def test(f):
  x = 99
  print(f())

test(x)