Is it possible to inherit a class in python without writing all the attributes in the definition?

2

I have the following sample code:

from Testes import POO
class Fisica(POO.Cliente):
    def __init__(self,sexo,nome,idade):
        super().__init__(nome,idade)
        self.sexo = sexo

Note that the attributes name and age are the attributes belonging to the parent class and so I would like to know if you can inherit a class without specifying all those attributes.

    
asked by anonymous 20.09.2018 / 03:15

1 answer

3

Yes -

The easiest way to do it is not perfect - but it's enough for most cases -

This is to make use of the mechanism that the language has to write functions that receive an arbitrary number of named parameters - for this, just precede the name of a parameter with two asterisks - ** (in almost all code Python you look at, this parameter will be called kwargs - short for "Keyword arguments" - or shortened to kw - however this is just a naming convention - the important thing is two ** .)

To shorten, your derived class above might look like this:

from Testes import POO
class Fisica(POO.Cliente):
    def __init__(self,sexo, **kwargs):
        super().__init__(**kwargs)
        self.sexo = sexo

Ready - what this means: The parameter sexo is required for the __init__ method of this subclass, and it does not mind receiving any other named parameters.

The kwargs parameter within this method will be a Python dictionary - normal, containing all the other arguments passed. You can inspect it, change it, etc ... (try putting print(kwargs) , for example).

And then, in the call to super()... the same kwargs is used in the reverse mechanism: when we put ** in the prefix of an argument in the call of a function or method, it assumes that the variable after ** is a mapping, a dictionary is a specific type of map) - and unfolds the contents chave: valor of that map as parameters and arguments to the called function.

In this case, if the Physical class was called with Fisica(sexo='F', nome='Simone', idade=35) , kwargs would be a dictionary containing {'nome': 'Simone', 'idade': 35} , and super().__init__(**kwargs) would be equivalent to super().__init__(nome='Simone', idade=35)

It is important to note that this syntax with two "**" requires arguments to be passed with a name - so Python can create a dictionary with par and value keys: ideally the call must be Fisica(sexo='F', nome='Simone', idade=35) . if it is desired to work with positional parameters. i.e.% with%, only one "*" should be used, and the parameter received with the other arguments in the order they were passed is a tuple, not a dictionary. Just because the signature with all possible / desired parameters is not explicit in the subclass, it is most recommended if working with named arguments, so no one needs to "guess" the send order, and calls can be in arbitrary order.

Note that this mechanism is very flexible - if you prefer, you can simply put Fisica('F', "Simone', 35) and no more parameters in the method definition, and extract the data used by each subclass of the dictionary itself, using the **kwargs method, for example (which retrieves a value from the dictionary and removes the corresponding key / value pair):

class Fisica(POO.Cliente):
    def __init__(self,sexo, **kwargs):
        self.sexo = kwargs.pop('sexo', '-')
        super().__init__(**kwargs)

(The second parameter for pop is the default value - in case, if the person did not pass "sex" as an argument, the string '-' would be used).

Why did I say that this is not perfect? Just because someone who inspects the .pop() method of the subclass can not see the names and specifications of the parameters in the superclass - only "sex" and "kwargs" would appear. So an IDE that relies on this to help you with the auto-complete, for example, will get lost.

A good recommendation in these cases is to document the extra parameters you know to be needed in the doc-string of the class.

Python's introspection mechanisms would allow the creation of a decorator for the class, for example, that could change the signature of the methods with kwargs within a class to reflect the parameters of the super-class - but that would be something very advanced, and complex. There may even be some external module that already does this.

    
20.09.2018 / 15:31