`x = 42 是怎么回事;x = lambda: x` 解析了吗?

max*_*max 47 python language-lawyer

我很惊讶这个断言失败了:

x = 42
x = lambda: x
assert x() == 42
Run Code Online (Sandbox Code Playgroud)

似乎x结束了递归指本身,这样x()x()()等都是功能。

用于解析它的规则是什么,它记录在哪里?

顺便说一句(不出乎意料地给出了上面的内容), 的原始值x在 lambda 定义之后没有引用:

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

x = X()
x = lambda: x  # 'deleting' is printed here
Run Code Online (Sandbox Code Playgroud)

mol*_*ilo 45

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

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

请注意,这不是动态范围 - 如果是动态范围,则以下内容将打印“99”,但会打印“<function ...”:

x = 42
x = lambda: x

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

test(x)
Run Code Online (Sandbox Code Playgroud)

  • 对,那是正确的。 (2认同)
  • 注意:与`nonlocal x; x = 99`,它*确实*打印 99。 (2认同)

Kar*_*tel 39

第一个任务无关紧要;的x主体中的lambda绑定晚了

x = lambda: x # no need for a prior assignment
x = lambda: y # notice: no NameError occurs, *until it is called*
Run Code Online (Sandbox Code Playgroud)

这与在循环创建 lambda 很棘手的原因相同,并且还用于使用标准库创建树defaultdict

tree = lambda: defaultdict(tree)
t = tree()
t['foo']['bar']['baz'] = 'look ma, no intermediate steps'
Run Code Online (Sandbox Code Playgroud)


tde*_*ney 12

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

x = lambda: x
Run Code Online (Sandbox Code Playgroud)

首先编译lambda: x成一个函数对象,该对象返回x调用它时发生的任何内容。然后它x与这个函数对象重新绑定,删除之前碰巧存在的任何对象。

现在x是一个返回任何内容x的函数......这是一个返回任何内容的函数x,等等......所以你可以x()()()()()()根据需要多次编写,并且仍然得到那个原始lambda:x函数对象。

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

def x():
    return x
Run Code Online (Sandbox Code Playgroud)

将此与

def x():
    x = 1
    return x
Run Code Online (Sandbox Code Playgroud)

现在,该参数x是一个局部变量,与 global 无关x