2015-05-21 7 views
5

Sto leggendo le classi in Python (3.4) e da quello che ho capito sembra che ogni nuovo oggetto abbia le proprie istanze dei metodi associati.Python crea davvero tutto il metodo associato per ogni nuova istanza?

class A: 

    def __init__(self, name): 
     self.name = name 

    def foo(self): 
     print(self.name) 

a = A('One') 
b = A('Two') 

print(a.foo == b.foo) 

L'output di questo è False.

Questo mi sembra uno spreco di memoria. Ho pensato che internamente a.foo e b.foo puntassero in qualche modo internamente a una funzione in memoria: A.foo dove self verrà passata l'istanza della classe.

Suppongo che questo non possa essere implementato facilmente nella lingua.

Ogni nuova istanza contiene anche nuove istanze dei relativi metodi associati?

In tal caso, ciò non pregiudica le prestazioni o crea spazio per la creazione di nuovi oggetti con maggiore cautela rispetto alle altre lingue in cui i metodi sono "condivisi" tra oggetti come in Java?

+0

Puoi collegare a qualcosa che hai letto che ti fa pensare che? –

+0

@SotiriosDelimanolis 'X(). F == X.f' genererà' False' (dove f è un metodo di instace). Questo è abbastanza per far pensare in questo modo. –

+0

Ogni metodo associato, tuttavia, fa riferimento alla stessa funzione sottostante. L'overhead di memoria per i wrapper è minimo. – chepner

risposta

14

I metodi sono legati su richiesta, ogni volta che si accede a uno.

L'accesso al nome di una funzione richiama lo descriptor protocol, che su oggetti funzione restituisce un metodo associato.

Un metodo associato è un involucro sottile attorno a un oggetto funzione; memorizza un riferimento alla funzione originale e all'istanza. Quando chiama un oggetto metodo, a sua volta passa la chiamata alla funzione, con l'istanza inserita come primo argomento.

I metodi non vengono creati quando l'istanza viene creata, quindi non è richiesta memoria aggiuntiva a priori.

È possibile ricreare le fasi manualmente:

>>> class A: 
...  def __init__(self, name): 
...   self.name = name 
...  def foo(self): 
...   print(self.name) 
... 
>>> a = A('One') 
>>> a.foo 
<bound method A.foo of <__main__.A object at 0x100a27978>> 
>>> a.foo.__self__ 
<__main__.A object at 0x100a27978> 
>>> a.foo.__func__ 
<function A.foo at 0x100a22598> 
>>> A.__dict__['foo'] 
<function A.foo at 0x100a22598> 
>>> A.__dict__['foo'].__get__(a, A) 
<bound method A.foo of <__main__.A object at 0x100a27978>> 
>>> A.__dict__['foo'].__get__(a, A)() 
One 

È solo l'oggetto metodo che viene ricreata ogni volta; la funzione sottostante rimane stabile:

>>> a.foo is a.foo 
False 
>>> b = A('Two') 
>>> b.foo is a.foo 
False 
>>> b.foo.__func__ is a.foo.__func__ 
True 

Questa architettura rende anche classmethod, staticmethod e property oggetti funzionano. È possibile creare i propri descrittori, creando un'intera serie di interessanti comportamenti vincolanti.

+0

Questa è la tua risposta anche qui, quindi ottieni il rep chiaramente non hai bisogno di più di entrambi i modi; o) – jonrsharpe

+0

@jonrsharpe: hah, ma questo è già accettato! :-P Non ho completamente riletto la domanda qui; in retrospettiva, sia la domanda che la risposta sono un duplicato perfetto. Ho avuto l'impressione che ci fosse dell'altro da spiegare nell'altro post. –