2012-04-04 11 views
23

basit örneği inceleyelim: LütfenPython bir sınıfın üyesi olan geri arama işlevini nasıl ayırt eder?

class A: 
    def __init__(self, flag): 
    self.flag = flag 

    def func(self): 
    print self.flag 

a = A(1) 
b = A(2) 
callback_a = a.func 
callback_b = b.func 

callback_a() 
callback_b() 

sonucudur:

1 
2 

O beklendiği çalışır olarak. Ama bir sorum var. C'de geri arama işlevi bir işaretçi olarak iletilir. Python'da, bunu yapmak için benzer bir yolu olmalı, böylece arayan işlevin adresini bilir. Ama benim örneğimde, sadece fonksiyon göstergesine geçilmiyor, aynı zamanda parametre (self) parametresi de aynı sınıftan farklı sonuçlar basıyor. Sorularım:

  1. Python'da böyle bir yöntemin yalnızca bir kopyası var mı? Benim anlamım, herhangi bir yöntemin kodunun yalnızca bir kopyası olmasıdır ve benim örneğimde yöntem klonlanmayacaktır. Sanırım sadece bir kopyası olmalı, ama burada daha fazla girdi elde etmek için hala bu soruyu yapıyorum.

  2. Python'daki her şeyin bir nesne olduğunu hatırlıyorum. Yani benim örneğimde, farklı parametrelere sahip iki fonksiyon örneği var, ancak sadece bir kod kopyası var mı?

+1

Bir kapanış oluşturmayı düşünür müsün? –

+0

Yeni stil sınıfları kullanıyor olmalısınız. Alt nesneyi 'nesneden' ya da alt sınıftan gelen şeyleri alt sınıflara ayırın. – aaronasterling

+1

@aaronasterling: Sorunun üzerinde çok fazla etkisi olduğundan emin değil miyim? – jdi

cevap

15

CPython'a özgü olarak, işlev nesnesinin yalnızca bir kopyası vardır. Örnek oluşturma sırasında, sınıf, ilişkisiz işlevleri ad alanındaki boş yöntemler olarak sarar. Ama hepsi aynı işlevi sarmaktadır.

İşte, örnek neler olup bittiğini göstermek için genişletildi.

class A(object): 
    def __init__(self, flag): 
    self.flag = flag 

    def func(self): 
    print self.flag 

a = A(1) 
b = A(2) 

callback_a = a.func 
callback_b = b.func 

print "typeof(callback_a) = {0}".format(type(callback_a)) 
print "typeof(callback_b) = {0}".format(type(callback_b)) 

print "typeof(callback_a.__func__) = {0}".format(type(callback_a.__func__)) 
print "typeof(callback_b.__func__) = {0}".format(type(callback_b.__func__)) 

print "'callback_a.__func__ is callback_b.__func__' is {0}".format(callback_a.__func__ is callback_b.__func__) 

callback_a() 
callback_b() 

Bu kod çıkışları hem instancemethod sınıflar aynı işlevi nesnesi paylaşımı olduğunu is operatörünü kullanarak

typeof(callback_a) = <type 'instancemethod'> 
typeof(callback_b) = <type 'instancemethod'> 
typeof(callback_a.__func__) = <type 'function'> 
typeof(callback_b.__func__) = <type 'function'> 
'callback_a.__func__ is callback_b.__func__' is True 

Sen açıkça görebilirsiniz,.

+2

Bunun neden başarısız olduğunu bilmek istiyorum. Eğer nesnel olarak yanlış bir şey varsa, bilmek isterim. – aaronasterling

+0

Gerçekten ilginç bulduğum şey, bu "print" 'callback_a, callback_b' isminin {0} ". Formatıdır (callback_a is callback_b)' print * false *. Javascript ve Perl'den geliyorum Bu davranışı gerçekten şaşırtıcı buluyorum. Bu konuda daha fazla söz veren Python belgeleri var mı? –

+2

'callback_a is callback_b'' False', çünkü her ikisi de 'AND ** fonksiyonunu tamamlayan bir' instancemethod'dur. Her ikisi de aynı "__func__" (ilk gönderide gösterildiği gibi) paylaşır, ancak her biri, bu işlevin çağrıldığı farklı bir "self" nesne örneğine sahiptir. Mantıklı olmak? – PfhorSlayer

17

Python'da geri arama, yalnızca üye işlevine yapılan bir başvuru değildir. Bunun yerine, oluşturulduğu zaman başvurduğu nesneye "bağlı" olur. Bu nedenle a.func, a'a bağlanan ve b.func, b'a bağlı bir satır oluşturur.

Python bellekte yalnızca func()'un bir uygulamasına gereksinim duyar, ancak büyük olasılıkla bir veya daha fazla "trampoline" işlevini bağlama işlemini gerçekleştirmek için çalışma zamanında oluşturacaktır (buradaki iç ayrıntılardan emin değilim, ve bunlar arasında farklılık olacaktır Python uygulamaları zaten).

id(callback_a) ve id(callback_b)'u yazdırırsanız, farklı sonuçlar elde edersiniz, bunlar gerçekten farklı satır nesnelerini gösterirler.

+1

Ve eğer id (b.func) == id (a.func) yaparsanız, aynı belleğe işaret ettiklerini görürsünüz – jdi

+0

Jdi: Bana neden "id (a.func)" farklı bir sonuç verdiğini söyler misiniz? her seferinde mi – mshsayem

+0

@mshsayem 'id', CPython'daki nesnenin bellek adresi olarak uygulanır. Yani program her çalıştığında bellekte farklı bir yer alıyor. – aaronasterling

İlgili konular