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

man*_*geo 31 python

我想使用class属性作为我的类__init__方法的一个参数的默认值.NameError但是,这个结构引发了一个异常,我不明白为什么:

class MyClass():
    __DefaultName = 'DefaultName'
    def __init__(self, name = MyClass.__DefaultName):
        self.name = name
Run Code Online (Sandbox Code Playgroud)

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

Fré*_*idi 28

那是因为,根据文件:

执行函数定义时,将评估默认参数值.这意味着在定义函数时,表达式将被计算一次

__init__()被定义,定义MyClass是不完整的,因为它仍然被解析,所以你不能参考MyClass.__DefaultName呢.解决这个问题的一种方法是传递一个特殊的唯一值__init__(),例如None:

def __init__(self, name=None):
    if name is None:
        name = MyClass.__DefaultName
    # ...
Run Code Online (Sandbox Code Playgroud)


Eth*_*man 23

使用Python 要记住的一个重要事项是执行不同的代码位,以及在查看时执行classdef语句的事实,而不仅仅是存储起来以备日后使用.有一点它更容易理解,因为唯一被执行的是s 之间的任何东西- 所以在上面的代码中def()

def __init__( SELF, name = MyClass.__DefaultName ):
Run Code Online (Sandbox Code Playgroud)

当Python看到MyClass.__DefaultName它试图首先在local命名空间中找到它,然后是模块(又名global)命名空间,最后在builtins.

local执行class语句时命名空间是什么?这是有趣的部分 - 它将成为class命名空间,但目前它是匿名的 - 所以你不能通过名称引用它(也就是MyClass在你的代码中),但你可以直接引用已经定义的任何东西. ..以及已定义的内容?在你的班级例子中只有一件事 - __DefaultName.所以你__init__应该看起来像这样:

def __init__( SELF, name=__DefaultName ):
Run Code Online (Sandbox Code Playgroud)

请记住,您MyClass._MyClass__DefaultName以后无法更改并在新实例中显示这些更改.为什么?因为__init__def只执行一次,并且__DefaultName当时存储的值已被存储并且将始终使用 - 除非您在创建新实例时直接指定新值:

my_instance = MyClass(name='new name')
Run Code Online (Sandbox Code Playgroud)