Reputation: 486
I tried to call the constructor of a class inside another class' constructor's parameter's default assignment, but I encountered this problem where the constructor isn't called correctly. What is happening here?
The Bad
class is the case that doesn't work and the Good
class is an ugly work around to solve the problem. The value Base.i
is incremented for every time the constructor Base.__init__
is called, and as can be seen, it isn't incremented correctly for the o2
object, but it seems to be incremented correctly for each of o1
, o3
and 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}")
o1.i: 1
o2.i: 1
Good:
o3.i: 2
o4.i: 3
Upvotes: 0
Views: 782
Reputation: 5935
Default arguments are evaluated at definition time, so here
class Bad:
def __init__(self, base = Base()):
self.base = base
the name base
(and hence self.base
) is assigned an instance of Base
at the time of definition already.
One way is to use a default of None
, as you already do in class Good
class Good:
def __init__(self, base = None):
if base is None:
self.base = Base()
else:
self.base = base
You could also define the __init__
of Bad
like this:
class Bad:
def __init__(self, base = Base):
self.base = base()
which will assign an instance of Base
when Bad
is initialized, not at definition time, so each instance of Bad
will have its own Base
.
If you want to able to pass arguments to base, you'd have to add options
class Bad:
def __init__(self, base = Base, base_args=(,), base_kwargs={}):
self.base = base(*base_args, **base_kwargs)
but in that case the None
way is simpler to use, since you can just pass the constructed instance directly.
Upvotes: 5