python - 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
为什么会发生这些事情以及如何处理默认参数值?
解决方案
三个事实:
- 默认参数的名称(左侧)是函数体内的局部变量名称。
- 默认参数的值(右侧)在定义函数时在定义函数的范围内进行评估。
- 类块中的代码在类定义期间在临时命名空间中执行。类块不被视为封闭范围,如果您期望类似于嵌套的行为,这可能会令人惊讶
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.bar
或self.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 中有更多关于怪异类范围的信息。
推荐阅读
- android - 从 Android 中的网站/应用程序对用户进行身份验证
- javascript - 我们可以在反应中创建静态成员吗?
- reactjs - 启用禁用 React Kendo Grid 中的字段/控件
- trace32 - Trace32:var.string 字符限制
- ios - 通过 UIActivityViewController 分享到 Instagram 故事?
- python - 在 Python 中删除 R 的函数
- java - 如何异步处理队列中的对象并在泽西岛进行发布请求
- java - Android Room - 无法在数据库中找到已插入的对象
- python - 循环多个值的多个生成器
- python - 冻结神经网络的权重,使其输出在特定点取特定值(张量流)