Đây là một lời giải thích rất dài mà tôi đã gõ cho một đồng nghiệp của mình. Tôi nghĩ rằng nó cũng sẽ hữu ích ở đây. Hãy kiên nhẫn, mặc dù. Tôi đi đến vấn đề thực sự mà bạn đang gặp phải cuối cùng. Cũng giống như một đoạn giới thiệu, đó là một vấn đề của việc có thêm tham chiếu đến các Line2D
đối tượng của bạn xung quanh.
CẢNH BÁO: Một lưu ý khác trước khi chúng ta đi sâu vào. Nếu bạn đang sử dụng IPython để kiểm tra điều này, thì IPython giữ các tham chiếu của riêng mình và không phải tất cả chúng đều là yếu. Vì vậy, thử nghiệm thu gom rác trong IPython không hoạt động. Nó chỉ làm rối ren vấn đề.
Được rồi, chúng ta bắt đầu. Mỗi matplotlib
đối tượng ( Figure
, Axes
v.v.) cung cấp quyền truy cập vào các nghệ sĩ con của nó thông qua các thuộc tính khác nhau. Ví dụ sau đây khá dài, nhưng sẽ sáng tỏ.
Chúng tôi bắt đầu bằng cách tạo một Figure
đối tượng, sau đó thêm một Axes
đối tượng vào hình đó. Lưu ý rằng ax
và fig.axes[0]
là cùng một đối tượng (giống nhau id()
).
>>>
>>> fig = plt.figure()
>>> fig.axes
[]
>>>
>>> ax = fig.add_subplot(1,1,1)
>>>
>>>
>>> print ax
Axes(0.125,0.1;0.775x0.8)
>>> print fig.axes[0]
Axes(0.125,0.1;0.775x0.8)
>>> id(ax), id(fig.axes[0])
(212603664, 212603664)
Điều này cũng mở rộng đến các dòng trong một đối tượng trục:
>>>
>>> lines = ax.plot(np.arange(1000))
>>>
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print lines[0]
Line2D(_line0)
>>> print ax.lines[0]
Line2D(_line0)
>>>
>>> id(lines[0]), id(ax.lines[0])
(216550352, 216550352)
Nếu bạn gọi plt.show()
bằng cách sử dụng những gì đã làm ở trên, bạn sẽ thấy một hình chứa một tập hợp các trục và một dòng:

Bây giờ, mặc dù chúng ta đã thấy rằng nội dung của lines
và ax.lines
đều giống nhau, nhưng điều rất quan trọng cần lưu ý là đối tượng được tham chiếu bởi lines
biến không giống với đối tượng được cung cấp lại bởi ax.lines
có thể thấy như sau:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
Do đó, việc xóa một phần tử khỏi lines
sẽ không ảnh hưởng gì đến cốt truyện hiện tại, nhưng xóa một phần tử khỏi ax.lines
sẽ xóa dòng đó khỏi cốt truyện hiện tại. Vì thế:
>>>
>>> lines.pop(0)
>>>
>>> ax.lines.pop(0)
Vì vậy, nếu bạn chạy dòng mã thứ hai, bạn sẽ xóa Line2D
đối tượng có trong ax.lines[0]
ô hiện tại và nó sẽ biến mất. Lưu ý rằng điều này cũng có thể được thực hiện thông qua ax.lines.remove()
nghĩa là bạn có thể lưu một Line2D
thể hiện trong một biến, sau đó chuyển nó ax.lines.remove()
để xóa dòng đó, như sau:
>>>
>>> lines.append(ax.plot(np.arange(1000)/2.0))
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]

>>>
>>> ax.lines.remove(lines[0])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84dx3>]

Tất cả những điều trên hoạt động fig.axes
cũng như nó hoạt động choax.lines
Bây giờ, vấn đề thực sự ở đây. Nếu chúng tôi lưu trữ tham chiếu có trong ax.lines[0]
một weakref.ref
đối tượng, sau đó cố gắng xóa nó, chúng tôi sẽ nhận thấy rằng nó không được thu thập rác:
>>>
>>> from weakref import ref
>>> wr = ref(ax.lines[0])
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
>>>
>>> ax.lines.remove(wr())
>>> ax.lines
[]
>>>
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
Tham khảo vẫn còn sống! Tại sao? Điều này là do vẫn còn một tham chiếu khác đến Line2D
đối tượng mà tham chiếu wr
trỏ tới. Hãy nhớ làm thế nào lines
không có cùng một ID ax.lines
nhưng chứa các phần tử giống nhau? Đó là vấn đề.
>>>
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
To fix this problem, we simply need to delete `lines`, empty it, or let it go out of scope.
>>>
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>
Vì vậy, đạo lý của câu chuyện là, hãy làm sạch sau khi chính mình. Nếu bạn mong đợi thứ gì đó được thu gom nhưng không có, bạn có khả năng để lại một tài liệu tham khảo đi chơi ở đâu đó.