Reputation: 443
If I had a parent class attribute that all of the child classes are going to inherit, can I set a default so that when the object is created, it automatically take the default from the parent class and no argument has to be given when creating it?
class F1(object):
def __init__(self, sick="flu"):
self.sick = sick
class F2(F1):
def __init__(self, sick, cure):
super(F2, self).__init__(sick)
self.cure = cure
a = F2("bed rest")
print(a.sick)
print(a.cure)
this is just a sample bit of code to show what I mean. I want every child to inherit the "sick" from the parent so I do not have to send that argument in when creating the object. Is this possible? Is there a different way of doing this same thing? Would it be better to make "sick" a class attribute?
Upvotes: 4
Views: 5326
Reputation: 48
I know this is 5 years old, but I came across it trying to figure out a related issue and saw it has 4k views. Just thought I'd suggest an alternative:
class F1(object):
def __init__(self, sick="flu"):
self.sick = sick
class F2(F1):
def __init__(self, cure="bed rest", **kwargs):
super().__init__(**kwargs)
self.cure = cure
a = F2(cure="wait it out")
print(a.sick) # => flu
print(a.cure) # => wait it out
a = F2(sick="covid", cure="quarantine")
print(a.sick) # => covid
print(a.cure) # => quarantine
a = F2(sick="anything")
print(a.sick) # => anything
print(a.cure) # => bed rest
(Of course, above works without declaring default value for cure
as well.)
You could also do it without calling with requiring keyword arguments like so:
class F1(object):
def __init__(self, sick="flu"):
self.sick = sick
class F2(F1):
# Without keyword arguments, must call args in order F2(cure, sick)
def __init__(self, cure="bed rest", *args, **kwargs):
super().__init__(*args, **kwargs)
self.cure = cure
a = F2("sleep")
print(a.sick) # => flu
print(a.cure) # => sleep
a = F2(sick="covid", cure="quarantine")
print(a.sick) # => covid
print(a.cure) # => quarantine
a = F2("sleep", "any sickness")
print(a.sick) # => any sickness
print(a.cure) # => sleep
Upvotes: 2
Reputation: 31284
the problem with your code is, that you are declaring F2.__init__
to have two explicit arguments, even though you only want to pass one.
If you want to be able to optionally override the creation argument of F1
you need to handle that yourself (see F3
)
class F1(object):
def __init__(self, sick="flu"):
self.sick = sick
class F2(F1):
def __init__(self, cure):
super(F2, self).__init__()
self.cure = cure
class F3(F1):
def __init__(self, cure, sick=None):
if sick is None:
super(F3, self).__init__()
else:
super(F3, self).__init__(sick)
self.cure = cure
a = F2("bed rest")
print("%s -> %s" % (a.sick, a.cure))
b = F3("inhale")
print("%s -> %s" % (b.sick, b.cure))
c = F3(sick="curiosity", cure="none")
print("%s -> %s" % (c.sick, c.cure))
Upvotes: 5
Reputation: 19328
Using super
is the standard way of doing this in Python. If you want to override, just override...
class F2(F1):
def __init__(self, sick, cure):
super(F2, self).__init__(sick)
self.cure = cure
self.sick = sick + 1
Adding class attribute could be an option, depending on your need. From your description, I'd say it sounds better, because the default value of sick
never change, and that's probably what you need.
Using class attribute does not affect overriding, because when assigning attribute on an instance, class attribute is not touched. An example:
>>> class F:
... a = 1
...
>>> f1, f2 = F(), F()
>>> f2.a = 2
>>> f1.a
1
Upvotes: 1