Nel nuove classi di stile (di default) e 3.x
ereditati da oggetto in 2.x
metodi attributo intercettazione __getattr__
e __getattribute__
are no longer called for built-in operations su Dunder sovraccarico metodi di istanze e invece la ricerca inizia con la classe.
La logica alla base di questo, comporta una tecnicità introdotta dalla presenza di MetaClass.
Poiché le classi sono istanze di metaclassi e poiché le metaclassi possono definire determinate operazioni che agiscono sulle classi, ignorare la classe (che in questo caso può essere considerata un instance
) ha senso; è necessario richiamare il metodo definito nel metaclass definito per elaborare le classi (cls
come primo argomento). Se è stata utilizzata la ricerca dell'istanza, la ricerca utilizza il metodo di classe definito per le istanze di tale classe (self
).
Altro (contestato ragione) coinvolge ottimizzazione: Dal momento che le operazioni di incasso sui casi di solito sono invocati molto spesso, saltando l'istanza look-up del tutto e andare direttamente alla classe ci salva un po 'di tempo.[Fonte Lutz, Imparare Python, 5th Edition]
Il area principale in cui questo potrebbe essere di inconveniente è durante la creazione di oggetti proxy che sovraccaricano __getattr__
e __getattribute__
con l'intenzione di inoltrare le chiamate al incorporato interna oggetto. Poiché l'invocazione integrata salterà del tutto l'istanza, non verrà catturata e un effetto non verrà inoltrato all'oggetto incorporato.
Un facile, ma noioso, work-around per questo è di sovraccaricare effettivamente tutti i dunder che si desidera intercettare nell'oggetto proxy. Quindi in questi dumper sovraccarichi è possibile delegare la chiamata all'oggetto interno come richiesto.
Il metodo più semplice work-around che posso pensare è impostare l'attributo della classe Foo
con setattr
:
setattr(Foo, '__call__', lambda *args: print(args))
f(1, 2, 3)
(<__main__.Foo object at 0x7f40640faa90>, 1, 2, 3)
fonte
2015-11-20 10:29:56
Per definire una per ogni istanza '__call__' implementazione Attualmente sto usando una classe -level '__call__' che inoltra a un membro normale. Tuttavia, sembra una brutta soluzione ... – 6502
@ 6502: questa è la soluzione consigliata. Se hai davvero bisogno di delegare a un callable per istanza, allora farlo in modo esplicito in un '__call__' a livello di classe è il modo migliore per farlo. –
@MartijnPieters Quale sarebbe un modo per aggirare tutti gli operatori ('__add__',' __rtruediv__', ecc.) In un intero archivio oggetti all'interno del proxy? Mi piacerebbe non implementare tutti i metodi manualmente se possibile. – danijar