可以使用类属性作为实例方法的默认值吗?
我想在我的类的 __init__
方法中,使用一个类属性作为某个参数的默认值。但是这样做会出现一个 NameError
的错误,我不明白为什么会这样:
class MyClass():
__DefaultName = 'DefaultName'
def __init__(self, name = MyClass.__DefaultName):
self.name = name
为什么会失败呢?有没有什么方法可以做到这一点呢?
2 个回答
在使用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
# ...