Quello che chiedi può essere fatto, e facilmente.Per esempio:
class dundersuper(super):
def __add__(self, other):
# this works, because the __getattribute__ method of super is over-ridden to search
# through the given object's mro instead of super's.
return self.__add__(other)
super = dundersuper
class MyInt(int):
def __add__(self, other):
return MyInt(super() + other)
i = MyInt(0)
assert type(i + 1) is MyInt
assert i + 1 == MyInt(1)
Quindi il motivo per cui super funziona con i metodi magici non è perché non è possibile. La ragione deve essere altrove. Uno dei motivi è che ciò violerebbe il contratto di pari diritti (==
). Questo è uguale, tra gli altri criteri, simmetrico. Ciò significa che se a == b
è vero, allora anche b == a
deve essere vero. Questo ci porta in una situazione difficile, dove super(self, CurrentClass) == self
, ma self != super(self, CurrentClass)
ad es.
class dundersuper(super):
def __eq__(self, other):
return self.__eq__(other)
super = dundersuper
class A:
def self_is_other(self, other):
return super() == other # a.k.a. object.__eq__(self, other) or self is other
def __eq__(self, other):
"""equal if both of type A"""
return A is type(self) and A is type(other)
class B:
def self_is_other(self, other):
return other == super() # a.k.a object.__eq__(other, super()), ie. False
def __eq__(self, other):
return B is type(self) and B is type(other)
assert A() == A()
a = A()
assert a.self_is_other(a)
assert B() == B()
b = B()
assert b.self_is_other(b) # assertion fails
Un altro motivo è che una volta eccellente è fatto searching è dato MRO dell'oggetto, esso deve poi darsi la possibilità di fornire l'attributo richiesto - oggetti eccellenti sono ancora un oggetto a sé stanti - dovremmo essere in grado di testare l'uguaglianza con altri oggetti, chiedere rappresentazioni di stringhe e introspezionare l'oggetto e la classe super con cui sta lavorando. Questo crea un problema se il metodo dunder è disponibile sull'oggetto super, ma non sull'oggetto rappresentato dall'oggetto mutabile. Per esempio:
class dundersuper(super):
def __add__(self, other):
return self.__add__(other)
def __iadd__(self, other):
return self.__iadd__(other)
super = dundersuper
class MyDoubleList(list):
"""Working, but clunky example."""
def __add__(self, other):
return MyDoubleList(super() + 2 * other)
def __iadd__(self, other):
s = super()
s += 2 * other # can't assign to the result of a function, so we must assign
# the super object to a local variable first
return s
class MyDoubleTuple(tuple):
"""Broken example -- iadd creates infinite recursion"""
def __add__(self, other):
return MyDoubleTuple(super() + 2 * other)
def __iadd__(self, other):
s = super()
s += 2 * other
return s
Con l'esempio lista la funzione __iadd__
avrebbe potuto essere più semplicemente scritto come
def __iadd__(self, other):
return super().__iadd__(other)
Con l'esempio tupla cadiamo in ricorsione infinita, questo è perché tuple.__iadd__
non esiste. Pertanto, quando si ricerca l'attributo __iadd__
su un superoggetto, l'oggetto super effettivo viene controllato per un attributo __iadd__
(che esiste). Otteniamo quel metodo e lo chiamiamo, che avvia di nuovo l'intero processo. Se non avessimo scritto un metodo __iadd__
su super e utilizzato super().__iadd__(other)
, questo non sarebbe mai successo. Piuttosto, riceviamo un messaggio di errore su un superoggetto che non ha l'attributo __iadd__
. Leggermente criptico, ma meno di una traccia di stack infinita.
Quindi la ragione super non funziona con i metodi magici è che crea più problemi di quanti ne risolva.
http://stackoverflow.com/questions/12047847/super-object-not-calling-getattr –
Anche utile: https://docs.python.org/3/reference/datamodel.html#special-method- look – wim