2015-05-12 9 views
7

Nuovo in Python e dopo aver letto un po ', sto facendo alcuni metodi nei miei metodi di classe classe personalizzati piuttosto che metodi di istanza.Python - perché posso chiamare un metodo di classe con un'istanza?

Così ho provato il mio codice, ma non aveva cambiato un po 'del metodo chiamate per chiamare il metodo della classe piuttosto che l'istanza, ma ancora lavorato:

class myclass: 
    @classmethod: 
    def foo(cls): 
     print 'Class method foo called with %s.'%(cls) 

    def bar(self): 
     print 'Instance method bar called with %s.'%(self) 

myclass.foo() 
thing = myClass() 
thing.foo() 
thing.bar() 

Questo produce:

class method foo called with __main__.myclass. 
class method foo called with __main__.myclass. 
instance method bar called with <__main__.myclass instance at 0x389ba4>. 

Quindi quello che mi chiedo è perché posso chiamare un metodo di classe (foo) su un'istanza (thing.foo), (anche se è la classe che viene passata al metodo)? Ha senso, dato che 'cosa' è un 'myClass', ma mi aspettavo che Python desse un errore dicendo qualcosa sulla falsariga di 'foo è un metodo di classe e non può essere chiamato su un'istanza'.

Questa è solo una conseguenza prevista dell'ereditarietà con l'oggetto "cosa" che eredita il metodo foo dalla sua superclasse?

Se provo a chiamare il metodo di istanza tramite la classe:

myclass.bar() 

tanto sono:

TypeError: unbound method bar() must be called with myclass instance... 

che ha perfettamente senso.

+0

In Python, i metodi non vengono chiamati * su * qualcosa. 'thing.foo' non è una chiamata al metodo, è un accesso agli attributi, è fondamentalmente la stessa cosa di' getattr (cosa, "pippo") '. – Alexey

+0

@Alexey Sicuramente 'foo' è un metodo e 'thing.foo()' sta chiamando il metodo 'foo' dell'oggetto' cosa'? Non è un attributo la terminologia di Python per ciò che altri linguaggi si riferiscono a una variabile o proprietà? –

+0

Penso che "' (thing.foo)() 'sta chiamando il metodo' foo' dell'oggetto 'cosa'" (parentesi per chiarezza) è una metafora per "' (thing.foo)() 'sta chiamando il oggetto chiamabile 'thing.foo'", è così. AFAIU, questo oggetto viene creato dinamicamente quando viene chiamato 'getattr (thing," foo ")' e ovviamente ha un riferimento all'oggetto 'thing'. – Alexey

risposta

6

È possibile chiamarlo su un'istanza perché @classmethod è un decorator (prende una funzione come argomento e restituisce una nuova funzione).

Ecco alcune informazioni relavent dal pitone documentation

Può essere chiamato sia nella classe (come Cf()) o un'istanza (ad esempio C(). F()) . L'istanza viene ignorata tranne che per la sua classe. Se viene invocato un metodo di classe per una classe derivata, l'oggetto classe derivata viene passato come primo argomento implicito.

C'è anche una buona discussione SO su @classmethodhere.

+0

Grazie - Ho effettuato varie ricerche per ereditarietà, metodi di classe ecc., Ma come potete immaginare, i risultati sono stati travolgenti. Sarei stato abbastanza felice di accettare semplicemente che funzioni, ma come programmatore assemblatore, mi piace sapere come funzionano le cose sotto le coperte. –

+0

"Puoi chiamarlo su un'istanza perché @classmethod è un decoratore" - non seguo questa logica. – Alexey

+0

@Alexey sai cos'è un decoratore? – John