使用内置名称作为局部变量,也作为内置变量

Mad*_*ist -2 python python-3.x

我有以下功能:

def x():
    print(min(0, 1))
    min = 7
    print(min)
Run Code Online (Sandbox Code Playgroud)

在它的面前(天真),它应打印0,然后7.实际上它引发了一个错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in x
UnboundLocalError: local variable 'min' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

定义min为局部变量如何min = 7防止它被用作手中的内置?Python是否__slots__在编译函数时构建局部变量列表(类似于类)?

Sha*_*ger 7

Python的编译阶段识别在函数范围内分配的所有名称,并将这些名称标记为本地(它们在CPython中的局部变量数组中被赋予索引,因此使用它们不涉及字典查找所有).

对于整个方法范围而言,作为一个本地是全有或全无.对于方法的一部分,您不能将变量视为本地变量,而对于其余部分,您不能将变量视为global/built-in.根据命名和绑定的语言参考:

范围定义块内名称的可见性.如果在块中定义了局部变量,则其范围包括该块.

像大多数语言标准一样,这是相当干燥的,但重要的是在块中定义局部变量使其(隐含的)整个块本地,而不是定义点.

如果你需要做这样的事情,你最初可以从内置的限定名称创建一个本地,然后在以后更改它,例如:

import builtins  # On Python 2, __builtin__

def x():
    min = builtins.min
    print(min(0, 1))
    min = 7
    print(min)
Run Code Online (Sandbox Code Playgroud)

或者你可以使用基于编译时默认值缓存的俗气黑客来达到同样的目的:

def x(min=min): # Caches builtin function as a default value for local min
    print(min(0, 1))
    min = 7
    print(min)
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Python 3,那么您希望def x(*, min=min):将其设置为仅关键字参数,因此如果它们无意中在位置上传递了太多参数,则不能被调用者覆盖.

  • @Kasramvd:是的,但这本身就很微妙.如果在第2行的顶层定义了阴影内置名称的全局,并且在第1行和第3行的顶层使用该名称,则会获得第1行的内置和第3行的阴影名称.本地化不会以这种方式工作,而全局变量使得LEGB的引用在这里不太有用.嵌套作用域甚至更奇怪,在外部作用域中的locals定义之前调用外部函数中的嵌套函数,并且内部函数print获得类似`<function foo.<locals> .bar at 0x7f5887930d08>`的值. (3认同)
  • @Kasramvd:LEGB定义了查找的顺序,但它本身并没有描述"本地"是整个块的事实,而不仅仅是从定义点开始. (2认同)