5

kullanmadan __get__ yoluyla __iadd__ çağrılırken, aşağıdaki davranış tökezledi Her iki vakanın da aynı davranmasını bekliyoruz. Dahası, referans sayımı ve nesne yaşamı anlayışımdan, her iki durumda da nesnenin serbest bırakılması gerektiğine ikna oldum.Bellek sızıntısı bir <code>weakref</code> kullanmak için bir dekoratör <em>değil</em> değiştirmek çalışırken geçici

Her ikisini de python2.7 ve python3.3'te test ettim.

Bu bir hata veya kasıtlı davranış mı? Her iki çağrının da beklenen sonuçlara sahip olması için bir yol var mı (söz konusu nesnenin serbest olması)? Bu ciltli yöntemleri için doğru nesne ömür boyu semantiğini yok eder çünkü

Ben proxy bir weakref kullanmak istemiyorsanız:

a = A() 
descr = a.descr 
del a # a is kept alive since descr is a bound method to a 
descr() # should execute a.descr() as expected 

cevap

5

iki codepaths eşdeğer değildir.

Yerinde ekleme işlemi, atama hedefi ve eklenen öğe olan iki operatöründe gerçekleştirilir. test1 olarak bu temp, bir yerel değişken ve yerinde ek çevrilir şöyledir:

temp = temp.__iadd__(object()) 

ve self dönmek ve temp bu temp = temp olur ve bu referans temizlenir, aynı nesneye işaret ettiğinden işlev çıktıktan sonra. test2 yılında

, sen karmaşık konular, şimdi tanımlayıcıları tekrar karışmaya beri:

a.descr += object() 

olur: a.descr öznitelik

a.descr = A.__dict__['descr'].__get__(a, A).__iadd__(object()) 

böylece örneğine A.__dict__['descr'].__get__(a, A) sonucunu atamak; Tanımlayıcı __set__() yöntemine sahip değildir ve danışılmamıştır.

Ama ve burada yakalamak olduğunu proxy nesne a bir başvuru kendisi tutar, a.descr.instancea için bir referans! Dairesel bir referans oluşturdunuz.

Bu başvuru nesnenin zayıf referansta gösterecek kadar uzun süre canlı kalmasını sağlar, ancak çöp toplama işlemi bu döngüyü çalıştırır ve bozar etmez, a yine de silinir.

Bu hikayenin ahlakı? __iadd__'u veri olmayan bir tanımlayıcıyla birlikte kullanmayın; Sonuç atandığında ne olacağını kontrol etmeniz gerektiğinden, hem __get__hem de__set__'u dahil edin.

+0

Gerçekten de, 'gc.collect()' ifadesini 'is_leaky' öğesine eklemek döngüsel referansı kırıyor ve' get_leaky (test2) 'işlevinin False değerini döndürmesine neden oluyor. – unutbu

+0

Evet, test2'nin a.descr .__ iadd __ (object()) olması için değiştirilmesi, ikinci bir False ile sonuçlanır. – BartoszKP

+1

WOW. Bu ince. Diskeçöre NOP '__set__' eklemek problemi düzeltir. Çok teşekkür ederim! – coldfix