python中关键字参数值的命名空间是什么?

时间:2019-10-09 23:26:54

标签: python python-3.x arguments

自从我了解

以来,我就知道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。 为什么会发生这些情况,以及如何处理默认参数值?

1 个答案:

答案 0 :(得分:4)

三个事实:

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

第3点是最微妙的,也许与最初的预期相反。它记录在execution model中( 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

请注意,bar0仍可通过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 why LEGB Rule not applied in this case中提供了有关怪异类范围的更多信息。