metodi speciali come __contains__
sono solo speciale quando definito sulla classe, non sulla istanza (se non in classi legacy in Python 2, che si dovrebbe non utilizzare comunque).
Quindi, fate la vostra delegazione a livello di classe:
class A(object):
def __init__(self):
self.mydict = {}
def __contains__(self, other):
return self.mydict.__contains__(other)
avrei in realtà preferisco di precisare quest'ultimo come return other in self.mydict
, ma questo è un problema di stile minore.
Edit: se e quando "totalmente dinamica reindirizzamento per-istanza di metodi speciali" (come le classi vecchio stile offerti) è indispensabile, non è difficile da attuare con classi di nuovo stile: è sufficiente ogni istanza che ha un così particolare bisogno di essere avvolto nella sua classe speciale. Per esempio:
class BlackMagic(object):
def __init__(self):
self.mydict = {}
self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
self.__class__.__contains__ = self.mydict.__contains__
In sostanza, dopo il po 'di magia nera riassegnazione self.__class__
a un oggetto di nuova classe (che si comporta proprio come il precedente, ma ha un dict vuota e non altri casi ad eccezione di questo self
), ovunque in una classe vecchio stile assegnata a self.__magicname__
, assegnare invece a self.__class__.__magicname__
(e assicurarsi che sia un built-in o staticmethod
, non una normale funzione Python, a meno che, naturalmente, in alcuni casi diversi si desideri ricevere il self
quando chiamato sull'istanza).
Per inciso, il in
operatore un'istanza di questa classe è BlackMagic
più veloce, come accade, che con qualsiasi delle soluzioni precedentemente proposte - o almeno così mi misura con la mia solita fidato -mtimeit
(andando direttamente allo built-in method
, invece di seguire normali percorsi di ricerca che coinvolgono ereditarietà e descrittori, rade un po 'del sovraccarico).
Un metaclasse per automatizzare l'idea di self.__class__
-per-istanza non sarebbe difficile da scrivere (potrebbe fare il lavoro sporco nel metodo __new__
della classe generata, e forse anche impostare tutti i nomi magici da assegnare effettivamente alla classe se assegnato nell'istanza, tramite __setattr__
o più, molte proprietà). Ma ciò sarebbe giustificato solo se la necessità di questa funzione fosse davvero diffusa (ad esempio, porting di un enorme progetto Python 1.5.2 che utilizza liberamente "metodi speciali per istanza" per Python moderno, incluso Python 3).
I raccomandare soluzioni "intelligenti" o "magia nera"?No, non lo faccio: quasi invariabilmente è meglio fare le cose in modo semplice e diretto. Ma "quasi" è una parola importante qui, ed è bello avere a portata di mano questi "ganci" avanzati per le rare, ma non inesistenti, situazioni in cui il loro uso potrebbe effettivamente essere giustificato.
Ok, questa è una spiegazione per me, ma non è del tutto soddisfacente per me, dal momento che questo tipo di delega costa più tempo (cosa potrei salvare in classi di vecchio stile - perché non dovrei usarli ??). – Juergen
"Le prestazioni ad ogni costo" non sono un buon obiettivo: "l'ottimizzazione prematura è la radice di ogni male nella programmazione" (Knuth, citando Hoare). Le classi in stile moderno sono funzionalmente più ricche, più generali, più regolari e più semplici (vedi la parte inferiore di p.103 di "Python in a Nutshell", che puoi leggere su Google Ricerca Libri - cerca "metodi per istanza"). In Python 3 e versioni successive, le classi precedenti sono finite per sempre - non legare il codice a loro per risparmiare nanosecondi di scarsa rilevanza. BTW, più veloce è quello di _inherit_ da dict (che ti dà anche una classe di nuovo stile). –
Ciao Alex, grazie per la lezione di tecniche di programmazione, io non bisogno ;-) Siamo spiacenti, ma non siamo bible-studiosi, quindi basta citare alcuni bible-versi o "grandi maestri" non è sufficiente per una buona me. Le altre spiegazioni sono buone, specialmente quelle sulle classi precedenti. Non voglio restare con i vecchi - ma voglio ragionare! La soluzione ereditaria mi è venuta in mente nel frattempo ed è soddisfacente per il mio problema speciale. Ancora le classi vecchio stile sono un po 'più flessibili/dinamici in questo punto (l'override peristanza di metodi speciali potrebbe essere buono anche in altre situazioni!) – Juergen