Viene generato un errore quando si tenta di impostare il valore di un argomento di una classe che eredita da str
. L'errore si verifica solo quando provo ad accedere all'argomento con myClass(arg = 'test')
. L'errore è:Impostare il valore di un argomento in una classe che eredita da int o float o str
TypeError: 'arg' is an invalid keyword argument for this function
La questione è mostrato in questa exemple:
class A(str):
def __init__(self, arg):
pass
A("test") # Works well
A(arg = "test") # Fails
solo l'ultima riga genera l'errore. La linea precedente funziona bene. Il problema è lo stesso con le classi che ereditano da int
o da float
.
UPDATE (soluzione):
ho trovato una soluzione con questi link:
- Adding optional parameters to the constructors of multiply-inheriting subclasses of built-in types?
- inheritance from str or int
La soluzione è:
class A(str):
def __new__(cls, *args, **kwargs):
return str.__new__(cls)
def __init__(self, arg01):
print(arg01)
A(arg01= "test")
Non so esattamente perché funzioni e indagherò su questo. Se qualcuno ha una spiegazione chiara, sono interessato e lo ringrazio in anticipo.
UPDATE (la mia spiegazione):
non sono sicuro affatto di ciò che sto per dire, ma che è quello che ho capito.
Immagina una classe 'myClass'
senza alcuna eredità. Quando faccio questo myInstance = myClass()
, ecco cosa succede:
Il metodo myClass.__new__
viene eseguito. Questo metodo creerà l'oggetto myInstance
. __new__
è il vero costruttore (__init__
non è un costruttore!). In pseudocodice, __new__
simile a questa:
def __new__ (cls, *args, **kwargs):
myInstance = # Do some stuff to create myInstance, an object of the type passed as argument (cls).
# Add the method __init__ to myInstance.
# Call __init__ and pass to it the list 'args' and the dictionary 'kwargs' (both come from arguments of __new__). Pass to it also the object itself (self) :
obj.__init__(self, args, kwargs) :
# Do some stuff.
La situazione è un po 'diverso quando stiamo usando tipi immutabili (str, int, float, tuple). Nello pseudocodice precedente, ho scritto def __new__(cls, *args, **kwargs)
. Con tipi immutabili, lo pseudocodice per il metodo __new__
è più simile a questo def __new__(cls, anUniqueValue)
. Non capisco davvero perché il comportamento di immutableTypes.__new__
sia diverso da altri, ma è il caso. Potete vederlo in questo esempio:
class foo():
def __init__(self):
pass
foo.__new__(foo, arg = 1)
# That works because the method __new__ look like this : def __new__(*args, **kargs).
str.__new__(str, arg = 1)
# That fails because we are trying to pass the attribute 'arg' to a method which look like this : def __new__(anUniqueValue).
Da lì, possiamo capire perché la soluzione presentata in precedenza funziona. Quello che facciamo è modificare il metodo __new__
di un tipo immutabile per funzionare proprio come un tipo mutabile.
def __new__(cls, *args, **kwargs):
return str.__new__(cls)
Queste 2 linee convertono def __new__ (cls, anUniqueValue)
a def __new__ (cls, *args, **kwargs)
Spero che la mia spiegazione è quasi chiaro e senza tanto errori.Se parli francese puoi saperne di più su questo link: http://sametmax.com/la-difference-entre-new-et-init-en-python/
Probabilmente correlato a http://stackoverflow.com/questions/3748635/adding-optional-parameters-to-the-constructors-of-multiply-inheriting-subclasses anche se non sono sicuro di ciò che Alex Martelli intende esattamente con ' superclasse altrettanto arbitraria ». – timgeb
@Morgan, la spiegazione è nella domanda collegata, potrebbe esserci anche una * lei * che può fornirti una spiegazione chiara;) –
@Morgan non esitare a rispondere alla tua stessa domanda quando hai scoperto cosa sta succedendo esattamente sopra. Non ho compreso appieno le spiegazioni nelle domande collegate. – timgeb