Reputation: 115
I'm trying to make a subclass that inherits from an instance of its superclass, and bases the majority of its attributes on the superclass attributes.
class Thing:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
class ThingWithD(Thing):
def __init__(self, thing, d):
self.a = thing.a
self.b = thing.b
self.c = thing.c
self.d = d
Is there a more concise way to make the a
, b
, and c
declarations inside ThingWithD.__init__()
?
Upvotes: 0
Views: 847
Reputation: 123521
The most concise—and object-oriented—way would probably be to just call the superclass's __init__()
method and avoid the repetition:
class Thing:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
class ThingWithD(Thing):
def __init__(self, thing, d):
super().__init__(thing.a, thing.b, thing.c) # Python 3 only
self.d = d
thing = Thing(1, 2, 3)
thing_with_d = ThingWithD(thing, 4)
print('{}, {}'.format(thing_with_d.a, thing_with_d.d)) # -> 1, 4
To do the same thing in Python 2.x, you would need to make Thing
a new-style class by explicitly specifying its base class as object
and change the call to the superclass constructor as shown below.
If you make both of these modifications, the same code will work in both Python 2 and 3.
class Thing(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
class ThingWithD(Thing):
def __init__(self, thing, d):
super(ThingWithD, self).__init__(thing.a, thing.b, thing.c)
self.d = d
Upvotes: 2
Reputation: 2424
With class Thing
defined as such:
class Thing:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
I can think of 3 ways to do achieve what you are asking using classical inheritence. The first, is to take advantage of your known arguments and explicitly index args
to pull out a to c, and d, like so:
class ThingWithD(Thing):
def __init__(self, *args):
self.d = args[-1]
a_to_c = args[:-1]
super().__init__(*a_to_c)
thing_with_d = ThingWithD(1,2,3,4)
thing_with_d.a # 1
thing_with_d.d # 4
The second, and best way, would be to convert your params to keyword arguments so that they can be more easily mixed and matched. This is the most scalable solution, and could pave the way for ThingWithE
and ThingWithF
.
class ThingWithD(Thing):
def __init__(self, d=None, **kwargs):
super().__init__(**kwargs)
self.d = d
thing_with_d = ThingWithD(a=1,b=2,c=3,d=4)
thing_with_d.a # 1
thing_with_d.d # 4
The last way, which seems closest to what you already tried, is to use ThingWithD
as a factory class that adds d to a class self referentially.
class ThingWithD(Thing):
def __init__(self, thing, d):
super().__init__(thing.a, thing.b, thing.c)
self.d = d
thing = Thing(1,2,3)
thing_with_d = ThingWithD(thing, 4)
thing_with_d.a # 1
thing_with_d.d # 4
This is a strange approach, because here we are actually creating a copy of the original thing
instance, and its unclear why we are inheriting from Thing
at all. Instead, we could use a function that does the following.
def add_d_to_thing(thing, d):
thing.d = d
return thing
thing = Thing(1,2,3)
thing_with_d = add_d_to_thing(thing, 4)
thing_with_d.a # 1
thing_with_d.d # 4
This would return the same instance of thing, would add a d
attribute, and is easier to read.
Upvotes: 1