cố gắng sửa đổi một trang trí không sử dụng một weakref
, tôi stumbled trên các hành vi sau đây:Memory rò rỉ khi gọi __iadd__ qua __get__ mà không sử dụng tạm thời
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!!!
Điều này có vẻ rất lạ với tôi, như tôi muốn mong cả hai trường hợp cư xử như nhau. Hơn nữa, từ sự hiểu biết của tôi về đếm tham chiếu và tuổi thọ đối tượng, tôi đã tin rằng trong cả hai trường hợp đối tượng cần được giải phóng.
Tôi đã thử nghiệm cả trên python2.7 và python3.3.
Đây có phải là lỗi hoặc hành vi có chủ ý không? Có cách nào để nhận cả hai cuộc gọi để có kết quả mong đợi (giải phóng đối tượng được đề cập)?
Tôi không muốn sử dụng một weakref
trong proxy
vì đây phá hủy ngữ nghĩa đối tượng đời đúng cho các phương pháp ràng buộc:
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
Thật vậy, việc thêm 'gc.collect()' vào 'is_leaky' sẽ phá vỡ tham chiếu vòng tròn và làm cho' is_leaky (test2) 'trả về False. – unutbu
Có, thay đổi test2 thành a.descr .__ iadd __ (object()) dẫn đến sai thứ hai. – BartoszKP
WOW. Điều này là tinh tế. Thêm một NOP '__set__' vào bộ mô tả để khắc phục sự cố. Cảm ơn nhiều! – coldfix