I want to make multiple inheritance, making a subclass inherit from two different super classes. This subclass should have an __init__ method in which the __init__ methods of the super classes are called with the expected arguments.
Here is an example that can illustrate my problem:
class Place:
def __init__(self, country, city, **attr):
self.country = country
self.city = city
self.attributes = attr
def show_location(self):
print(self.country, self.city)
class Product:
def __init__(self, price, currency = '$'):
self.price = price
self.currency = currency
def show_price(self):
print(self.price, self.currency)
class Flat(Place, Product):
def __init__(self, country, city, street, number, price, currency = '$', **attr):
super(Place).__init__(country, city, **attr)
super(Product).__init__(price, currency)
self.street = street
self.number = number
def show_address(self):
print(self.number, self.street)
myflat = Flat('Mozambique', 'Nampula', 'Rua dos Combatentes', 4, 150000, '$')
But I don't really know how to use the super() method, and this code throws the following error:
TypeError: super() argument 1 must be type, not str
I wonder how can I initialize the Flat object both as a Place and as a Product...
Is it appropriate to use super() in this context?
Or is it better to call __init__ directly this way: SuperClass.__init__(self, ...) ?
TL;DR The article Python’s super() considered super! explains in detail how to use
supercorrectly.superis intended to implement cooperative multiple inheritance, where the classes involved are designed together to support such inheritance. This requires redesigning bothPlaceandProductslightly; the linked article discusses the rationale for the redesign shown below. (If you can't redesign them, the linked article also explains how to define adaptor classes to wrap them.)The key is that
superrefers to the next class in the method resolution order (MRO), a list of classes constructed from the inheritance tree. Only one call tosuperis required in each method. BothPlaceandProductuse it as well, because neither class knows if it will be the last class in the MRO of the object being initialized. (More precisely, both know they won't, becauseobjectitself is always the final class.)Each
__init__method accepts a certain number of keyword-only arguments that it knows what to do with, along with arbitrary keyword arguments that it will pass on to one of the ancestor class to handle. Ultimately, if the classes are defined correctly, one of the calls tosuper().__init__(**kwargs)will invokeobject.__init__with no keyword arguments, ending the chain.