首页 > 解决方案 > python中关键字参数值的命名空间是什么?

问题描述

我知道自从我发现 python 以不同的方式处理这个命名空间

def foo(l=[]):
    l.append(1)
    print(l)

foo()
foo()
foo([])
foo()

打印以下内容。

[1]
[1,1]
[1]
[1,1,1]

所以我对它们作为对象初始化器的使用持怀疑态度。然后最近我遇到了另一个类似的奇怪行为,如下所示。

class Foo:
    bar = 0
    def __init__(self):
        self.a = bar
Foo()

bar这引发了一个未在此命名空间内定义的异常。

class Foo:
   bar = 0
   def __init__(self, a=bar)
       self.a = a
Foo()

现在这成功地将类变量保存的值分配给初始化程序内foo的对象。a为什么会发生这些事情以及如何处理默认参数值?

标签: pythonpython-3.xarguments

解决方案


三个事实:

  1. 默认参数的名称(左侧)是函数体内的局部变量名称。
  2. 默认参数的(右侧)在定义函数时在定义函数的范围内进行评估。
  3. 类块中的代码在类定义期间在临时命名空间中执行。类块不被视为封闭范围,如果您期望类似于嵌套的行为,这可能会令人惊讶def

第 3 点是最微妙的,也许与最初的预期相反。它记录在执行模型中(第4.2.2 节。名称解析):

类块中定义的名称范围仅限于类块;它没有扩展到方法的代码块

这就是为什么bar在您的第二个示例中未解析名称的原因:

class Foo:
    bar = 0
    def __init__(self):
        self.a = bar  # name "bar" isn't accessible here, but code is valid syntax

Foo()  # NameError: name 'bar' is not defined

请注意,bar值 ,0仍然可以从方法中作为类属性访问:通过Foo.barself.bar

您现在应该明白为什么最后一个示例确实有效:

class Foo:
   bar = 0
   def __init__(self, a=bar):
       self.a = a
Foo()

而且,考虑到上面的第 1-3 点,您还应该能够正确预测这里会发生什么:

class Foo:
   def __init__(self, a=bar):
       self.a = a
   bar = 0
Foo()

在UnboundLocalError: local variable referenced before assignment 为什么 LEGB Rule not applicable in this case 中有更多关于怪异类范围的信息。


推荐阅读