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

Asked

Viewed 239 times

2

I have the following example 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 name and age attributes are the attributes belonging to the mother class and so I would like to know if you can inherit a class without specifying all these attributes.

  • You do not want to pass the parameters on super().__init__() ? There is another post here that talks about it may help. https://answall.com/questions/22452/como-se-usa-e-para-para-serve-o-super-em-classes-python

1 answer

3


Yes -

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

It is about making use of the mechanism that the language has to write functions that receive an arbitrary number of parameters with name - for this, just precede the name of a parameter with two asterisks - ** (in almost every Python code you look at, this parameter will be called kwargs - abbreviation of "Keyword Arguments" - or shortened to kw - however this is only a name convention - the important are the two **.)

To make a long story short, your derivative class above could look like this:

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

Ready -what that means: the parameter sexo is mandatory for the method __init__ of this subclass, and it does not care to receive any other parameters named.

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

And then on the call to super()... the same kwargs is used in 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 the ** is a map ( "Mapping", a dictionary is a specific type of map) - and unfolds the contents chave: valor of this map as parameters and arguments for the called function.

In that case, if the Physics 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 that arguments be passed with name - only so can Python create a dictionary with pair and value keys: that is, ideally the call has to be Fisica(sexo='F', nome='Simone', idade=35). if it is desired to work with positional parameters. i.e. Fisica('F', "Simone', 35), 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. Precisely because the signature with all possible/desired parameters is not explicit in the subclass, it is more recommended to work with the arguments with name, so no one needs to "guess" the sending order, and the calls can be in arbitrary order.

Note that this mechanism is quite flexible - if you prefer, you can simply put **kwargs and no further parameters in the method definition, and extract the data used by each subclass from the dictionary itself, with the method .pop(), for example (that recovers a dictionary value 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 this case, if the person did not pass "sex" as argument, the string '-' would be used).

Why did I tell you this isn’t perfect? Just because so someone who enters the method __init__ of the subclass has no way of seeing 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 auto-complete, for example, will get lost.

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

Python’s introspection mechanisms allowed the creation of a class-to-class Decorator, for example, that could change the signature of methods with kwargs within a class to reflect the parameters of the super-class - but this would be something very advanced, and complex. It is even possible that there is some external module that already does this.

  • Guy worked, but for some reason it worked only with a *, in case *kwargs, but anyway, thank you so much!

  • 1

    A single "*" has a different sense - it’s for positional arguments, sent unnamed - the resulting object, within the method, is a tuple, not a dictionary - you have access to the values sequentially, but without the names. Other than that, it also works - if whoever calls the method passes the arguments in the expected sequence. (and is usually called args, not of kwargs)

  • 1

    I added a paragraph to talk about the positional arguments.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.