调用类的构造函数作为其他类构造函数中的默认参数

dek*_*rub 0 python constructor initialization default-constructor default-arguments

问题

我试图在另一个类的构造函数的参数的默认赋值中调用一个类的构造函数,但是我遇到了构造函数未正确调用的问题。这里发生了什么?

代码说明

Bad类是不工作的情况和Good类是一个丑陋的解决办法来解决这个问题。Base.i每次Base.__init__调用构造函数时,该值都会增加,并且可以看出,它没有为o2对象正确增加,但似乎为每个o1,o3和正确增加o4

代码

class Base:
    i = 0
    def __init__(self):
        Base.i += 1
        self.i = Base.i

class Bad:
    def __init__(self, base = Base()):
        self.base = base

class Good:
    def __init__(self, base = None):
        if base is None:
            self.base = Base()
        else:
            self.base = base

if __name__ == "__main__":
    o1 = Bad()
    o2 = Bad()

    print("Bad:")
    print(f"o1.i: {o1.base.i}")
    print(f"o2.i: {o2.base.i}")

    o3 = Good()
    o4 = Good()

    print("Good:")
    print(f"o3.i: {o3.base.i}")
    print(f"o4.i: {o4.base.i}")
Run Code Online (Sandbox Code Playgroud)

输出

o1.i: 1
o2.i: 1
Good:
o3.i: 2
o4.i: 3
Run Code Online (Sandbox Code Playgroud)

Jan*_*asa 5

默认参数在定义时计算,所以这里

class Bad:
    def __init__(self, base = Base()):
        self.base = base
Run Code Online (Sandbox Code Playgroud)

名称base(因此self.baseBase在定义时已经分配了一个实例。

一种方法是使用默认值 of None,就像您已经在class Good

class Good:
    def __init__(self, base = None):
        if base is None:
            self.base = Base()
        else:
            self.base = base
Run Code Online (Sandbox Code Playgroud)

你也可以定义__init__Bad是这样的:

class Bad:
    def __init__(self, base = Base):
        self.base = base()
Run Code Online (Sandbox Code Playgroud)

这将分配初始化Base时的实例Bad,而不是在定义时,因此每个实例Bad都有自己的Base.

如果您想将参数传递给 base,则必须添加选项

class Bad:
    def __init__(self, base = Base, base_args=(,), base_kwargs={}):
        self.base = base(*base_args, **base_kwargs)
Run Code Online (Sandbox Code Playgroud)

但在这种情况下None,使用方法更简单,因为您可以直接传递构造的实例。