我想将类属性作为我的类 __init__
方法的一个参数的默认值。但这个结构会引发 NameError
异常,我不明白为什么会出现这种情况:
class MyClass():
__DefaultName = 'DefaultName'
def __init__(self, name = MyClass.__DefaultName):
self.name = name
为什么这个失败了,有没有一种方法可以做到这一点?
我想将类属性作为我的类 __init__
方法的一个参数的默认值。但这个结构会引发 NameError
异常,我不明白为什么会出现这种情况:
class MyClass():
__DefaultName = 'DefaultName'
def __init__(self, name = MyClass.__DefaultName):
self.name = name
为什么这个失败了,有没有一种方法可以做到这一点?
在Python中需要牢记的一件重要事情是代码的不同部分被执行的时间,以及class
和def
语句在被查看时就会被执行,而不仅仅是被存储起来。对于def
,理解起来要容易一些,因为唯一被执行的是()
之间的内容 —— 所以,在你上面的代码中,
def __init__( SELF, name = MyClass.__DefaultName ):
当Python看到MyClass.__DefaultName
时,它首先在local
命名空间中查找,然后在模块(即global
)命名空间中查找,最后在builtins
中查找。class
语句时,local
命名空间是什么? 这就是有趣的部分 - 它将成为class
的命名空间,但此时它是匿名的 - 因此您无法通过名称(即您代码中的MyClass
)引用它,但是您可以直接引用已经定义的任何内容...已经定义了什么呢? 在您的类示例中只有一件事 - __DefaultName
。 因此,您的__init__
应该如下所示:def __init__( SELF, name=__DefaultName ):
请记住,您无法在稍后更改MyClass._MyClass__DefaultName
并使这些更改在新实例中显示。为什么?因为__init__
方法只执行一次,并且在那个时刻__DefaultName
的任何值都已被存储,并且将始终使用该值 - 除非您在创建新实例时直接指定新值:
my_instance = MyClass(name='new name')
这是因为根据文档的描述:
默认参数值在函数定义时被计算。 这意味着表达式只会在函数定义时被计算一次。
当定义__init__()
时,MyClass
的定义尚不完整,因为它仍在解析中,所以你还不能引用MyClass.__DefaultName
。解决这个问题的方法之一是向__init__()
传递一个特殊的唯一值,例如None
:
def __init__(self, name=None):
if name is None:
name = MyClass.__DefaultName
# ...
type(self)
可以吗? - Alexey