próbuje modyfikować dekorator nie użyć weakref
, natknąłem się na następujące zachowanie:wyciek pamięci podczas wywoływania __iadd__ poprzez __get__ bez stosowania tymczasowego
import weakref
class descriptor(object):
def __get__(self, instance, owner):
return proxy(instance)
class proxy(object):
def __init__(self, instance):
self.instance = instance
def __iadd__(self, other):
return self
class A(object):
descr = descriptor()
def is_leaky(test_fn):
a = A()
wr = weakref.ref(a)
test_fn(a)
del a
return wr() is not None
def test1(a):
tmp = a.descr
tmp += object()
def test2(a):
a.descr += object()
print(is_leaky(test1)) # gives False
print(is_leaky(test2)) # gives True!!!
to wydaje bardzo dziwne dla mnie, jak ja oczekiwać, że oba przypadki zachowują się tak samo. Co więcej, z mojego rozumienia liczenia odnośników i czasu życia obiektów byłem przekonany, że w obu przypadkach obiekt powinien zostać uwolniony.
Przetestowałem to zarówno na python2.7, jak i python3.3.
Czy to błąd, czy zamierzone zachowanie? Czy istnieje sposób na uzyskanie obu połączeń, aby uzyskać oczekiwane wyniki (zwolnić dany obiekt)?
Nie chcę używać weakref
w proxy
bo to niszczy prawidłowe semantykę obiektu dożywotnie metod związanych:
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
Rzeczywiście, dodanie 'gc.collect()' do 'is_leaky' powoduje przerwanie odwołania cyklicznego i powoduje, że' is_leaky (test2) 'zwraca false. – unutbu
Tak, zmiana test2 na a.descr .__ iadd __ (object()) skutkuje drugim fałszem. – BartoszKP
WOW. To jest subtelne. Dodanie NOP '__set__' do discriptora rozwiązuje problem. Dziękuję Ci bardzo! – coldfix