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.
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– pic