`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
正文中的 x
是 bound 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)
令我惊讶的是这个断言失败了:
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
正文中的 x
是 bound 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)