我想使用class属性作为我的类__init__
方法的一个参数的默认值。但是,这个结构引发了NameError
异常,我不明白为什么:
class MyClass():
__DefaultName = 'DefaultName'
def __init__(self, name = MyClass.__DefaultName):
self.name = name
为什么这会失败,有没有办法做到这一点?
答案 0 :(得分:28)
那是因为,根据documentation:
在函数定义时计算默认参数值 执行。这意味着 表达式被评估一次,当时 函数已定义
定义__init__()
时,MyClass
的定义不完整,因为它仍在解析中,因此您无法引用MyClass.__DefaultName
。解决此问题的一种方法是将特殊唯一值传递给__init__()
,例如None
:
def __init__(self, name=None):
if name is None:
name = MyClass.__DefaultName
# ...
答案 1 :(得分:22)
在执行不同位代码时,要记住Python的一个重要事项是以及在class和def
语句这一事实>见过,不仅仅是为了以后存储起来。使用def
它会更容易理解,因为唯一要执行的是()
之间的任何内容 - 所以在上面的代码中
def __init__( SELF, name = MyClass.__DefaultName ):
当Python看到MyClass.__DefaultName
时,它首先尝试在local
命名空间中找到它,然后是模块(又名global
)命名空间,最后在builtins
中找到它。
执行local
语句时class
命名空间是什么?这是有趣的部分 - 它将成为class
命名空间,但目前它是匿名的 - 所以你不能通过名称引用它(在你的代码中也称为MyClass
)但是你可以直接引用已定义的任何内容......以及已定义的内容?在您的课程示例中只有一件事 - __DefaultName
。所以你的__init__
应该是这样的:
def __init__( SELF, name=__DefaultName ):
请注意,您以后无法更改MyClass._MyClass__DefaultName
并在新实例中显示这些更改。为什么?因为__init__
def只执行一次,并且当前存储的值__DefaultName
已被存储并且将始终使用 - 除非您在创建新实例时直接指定新值:
my_instance = MyClass(name='new name')