2012-10-13 13 views
8

Oltre a ignorare qualsiasi attributo di istanza nell'interesse della correttezza, la ricerca implicita del metodo speciale generalmente ignora anche il metodo __getattribute__() anche del metaclasse dell'oggetto.Quali metodi speciali aggirano __getattribute__ in Python?

The docs menzione metodi speciali come __hash__, __repr__ e __len__, e so per esperienza che include anche __iter__ per Python 2.7.

Per citare an answer to a related question:

"Magic __methods__() vengono trattati in maniera particolare: Essi vengono assegnati internamente a 'slot' nella struttura del tipo di dati per accelerare il loro look-up, e sono solo guardato in questi slot ".

In una ricerca per migliorare la mia risposta a another question, ho bisogno di sapere: quali metodi, in particolare, stiamo parlando?

+0

Quali metodi sono assegnati agli slot? –

+7

Penso che ogni metodo elencato [qui] (http://docs.python.org/reference/datamodel.html#specialnames). Comunque considera che questo si applica solo se chiami il metodo usando "la sua sintassi". Ad esempio, 'a + 5' non chiamerà' __getattribute__', mentre 'a .__ add __ (5)' * lo chiamerà *. Fondamentalmente '__getattribute__' viene chiamato ogni volta che si usa il punto (' .') per accedere a un attributo. – Bakuriu

+0

@Bakuriu: molto informativo, grazie. – porgarmingduod

risposta

4

Si può trovare una risposta nella python3 documentation per object.__getattribute__, in cui si afferma:

Chiamato incondizionatamente per implementare l'attributo di accessi per le istanze della classe. Se la classe definisce anche __getattr__(), l'ultimo numero non verrà chiamato a meno che lo lo chiami esplicitamente o lo sollevi o crei un'eccezione AttributeError. Questo metodo dovrebbe restituire il valore dell'attributo (calcolato) o sollevare un'eccezione AttributeError. In per evitare la ricorsione infinita in questo metodo, la sua implementazione deve sempre chiamare il metodo della classe base con lo stesso nome per accedere a qualsiasi attributo necessario, ad esempio, oggetto. __getattribute__(self, name).

Nota

Questo metodo può ancora essere bypassato durante la ricerca di metodi speciali come il risultato di un'invocazione implicita tramite sintassi del linguaggio o incorporati in funzioni. Vedi la ricerca metodo speciale.

anche this pagina spiega esattamente come funziona questo "macchinario". Fondamentalmente __getattribute__ viene chiamato solo quando si accede ad un attributo con l'operatore . (punto) (e anche da hasattr come indicato da Zagorulkin).

nota che la pagina non specifica quali metodi speciali sono implicitamente alzò gli occhi, quindi ho ritenuto che questa presa per tutti loro (che si possono trovare here.

+0

hai effettivamente controllato? ho fatto il check in 2.7.9 e sembra che i documenti non abbiano proprio ragione. –

1

Controllato in 2.7.9

Couldn 't trovare un modo per aggirare la chiamata a __getattribute__, con uno dei metodi magici che si trovano sul object o type:

# Preparation step: did this from the console 
# magics = set(dir(object) + dir(type)) 
# got 38 names, for each of the names, wrote a.<that_name> to a file 
# Ended up with this: 

a.__module__ 
a.__base__ 
#... 

mettere questo al beginnin g di quel file, che ho rinominato in un vero modulo python (asdf.py)

global_counter = 0 

class Counter(object): 
    def __getattribute__(self, name): 
     # this will count how many times the method was called 
     global global_counter 
     global_counter += 1 
     return super(Counter, self).__getattribute__(name) 

a = Counter() 
# after this comes the list of 38 attribute accessess 
a.__module__ 
#... 
a.__repr__ 
#... 

print global_counter # you're not gonna like it... it printer 38 

poi ho anche cercato di ottenere ciascuno di questi nomi con getattr e hasattr -> stesso risultato. __getattribute__ è stato chiamato ogni volta.

Quindi se qualcuno ha altre idee ... ero troppo pigro per guardare dentro il codice C, ma sono sicuro che la risposta sta da qualche parte lì.

Quindi o c'è qualcosa che non sto andando bene, oi documenti stanno mentendo.

+1

Se ricordo male, la mia domanda riguardava 'repr (a)' in opposizione a 'a .__ repr __()'. È passato un po 'di tempo da quando ero in questa roba, ma suppongo che tu abbia la versione getattribute perché cerchi attributi, mentre i metodi incorporati di cui stiamo parlando (il globale 'repr', non' __repr__') aggira l'esistenza di '__repr__'. – porgarmingduod

+0

Sostituisci '__getattribute__' per emettere una stampa ogni volta che viene chiamata e poi fai:' Counter ('a') + Counter ('a') 'e vedi che non stampa nulla. Perché ignora il nome standard e colpisce 'Counter .__ dict __ ['__ add __']' direttamente o qualcosa del genere nel nome dell'ottimizzazione. – justanr

Problemi correlati