【问题标题】:What is a keyword argument value's namespace in python?python中关键字参数值的命名空间是什么?
【发布时间】:2020-02-07 08:13:57
【问题描述】:

自从我发现

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。 为什么会发生这些事情?如何处理默认参数值?

【问题讨论】:

  • bar 在类范围内的特殊性问题与默认值问题有点正交。您需要了解的是,类主体不会形成封闭范围,这就是为什么您必须始终在类主体中定义的方法的函数主体内使用self.bar。还要注意,values 没有命名空间本身,相反,不同的命名空间可以引用相同的值。但是,默认值在函数定义时被评估一次,并且它们可以访问为您使用的任何表达式定义函数的范围
  • 关于“命名空间”问题,如果您想知道函数的默认参数实际存储在哪里,也可以查看this page 并查找__defaults__

标签: python python-3.x arguments


【解决方案1】:

三个事实:

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

第 3 点是最微妙的,可能与最初的预期相反。它记录在execution model4.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 中有更多关于怪异类作用域的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-24
    • 2012-09-29
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    • 2011-03-23
    相关资源
    最近更新 更多