关于python:我可以使用class属性作为实例方法的默认值吗?

Can I use a class attribute as a default value for an instance method?

我想使用类属性作为类的__init__方法的参数之一的默认值。不过,这个构造引发了一个NameError异常,我不明白为什么:

1
2
3
4
class MyClass():
    __DefaultName = 'DefaultName'
    def __init__(self, name = MyClass.__DefaultName):
        self.name = name

为什么失败了,有没有办法做到这一点?


这是因为,根据文件:

Default parameter values are evaluated when the function definition
is executed. This means that the
expression is evaluated once, when the
function is defined

当定义__init__()时,MyClass的定义不完整,因为它仍在被解析,所以您还不能引用MyClass.__DefaultName。解决这一问题的一种方法是将一个特殊的唯一值传递给__init__(),例如None

1
2
3
4
def __init__(self, name=None):
    if name is None:
        name = MyClass.__DefaultName
    # ...


对于python,需要记住的一件重要的事情是,执行不同的代码位时,以及当看到classdef语句时执行,而不仅仅是存储以后执行。对于def,理解起来要容易一点,因为执行的唯一一件事就是()之间的任何东西——所以在上面的代码中

1
def __init__( SELF, name = MyClass.__DefaultName ):

当python看到MyClass.__DefaultName时,它试图首先在local名称空间中找到它,然后在module(aka global名称空间中找到它,最后在builtins中找到它。

执行class语句时,local命名空间是什么?这是有趣的部分——它将成为class名称空间,但目前它是匿名的——所以您不能通过名称(在代码中称为MyClass)引用它,但您可以直接引用已经定义的任何内容……定义了什么?在您的类示例中,只有一件事——__DefaultName。所以你的__init__应该是这样的:

1
def __init__( SELF, name=__DefaultName ):

记住,以后不能更改MyClass._MyClass__DefaultName,并且这些更改会出现在新的实例中。为什么?因为__init__def只执行一次,而此时__DefaultName的任何值都已存储并将一直使用,除非您在创建新实例时直接指定一个新值:

1
my_instance = MyClass(name='new name')