2017-07-19 141 views
1

我有一個關於Python中的內存管理的問題,具體涉及到使用Tkinter的程序。首先我將以一個例子來展示我測試一些簡單的內存管理:內存管理和Tkinter

import tkinter as tk 
from tkinter import ttk 

class Frame1(tk.Frame): 

    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent, *args, **kwargs) 
     self.parent = parent 
     self.pack() 
     print("Frame1 created") 
     btn = ttk.Button(self, text = "PRESS", command = self.openFrame2) 
     btn.pack() 

    def __del__(self): 
     print("Frame1 destroyed") 

    def openFrame2(self): 
     self.pack_forget() 
     self.destroy() 
     frame2 = Frame2(self.parent) 

class Frame2(tk.Frame): 

    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent, *args, **kwargs) 
     self.parent = parent 
     self.pack() 
     print("Frame2 created") 
     btn = ttk.Button(self, text = "CLICK", command = self.openFrame1) 
     btn.pack() 

    def __del__(self): 
     print("Frame2 destroyed") 

    def openFrame1(self): 
     self.pack_forget 
     self.destroy() 
     frame1 = Frame1(self.parent) 

root = tk.Tk() 
program = Frame1(root) 
root.mainloop() 

這個程序的目標很簡單。用一個按鈕創建一個包含Frame的Tkinter窗口。按下該按鈕時,刪除該幀,釋放由該幀使用的內存,並創建一個不同的幀。

如果我按在PRESS -> CLICK -> PRESS我的預期結果的順序按一下按鈕是:

Frame1 created 
PRESS: 
Frame1 destroyed 
Frame2 created 
CLICK: 
Frame2 destroyed 
Frame1 created 
PRESS: 
Frame1 destroyed 
Frame2 created 

而不是我的實際結果是:

Frame1 created 
PRESS: 
Frame2 created 
CLICK: 
Frame1 created 
Frame2 destroyed 
PRESS: 
Frame2 created 
Frame1 destroyed 

我有點困惑在這裏。 Frame2似乎正確呼叫__del__方法時,我呼籲self.destroy()Frame1不。爲什麼是這樣?

+0

Python不保證何時(或甚至)是否調用'__del __()',它不是C++。最好忘記嘗試使用它來做到這一點。而是考慮在派生類中重載'destroy()'。 – martineau

+0

FWIW:這什麼都不做:'self.pack_forget'。即使你正確地調用了它('self.pack_forget()'),你之後立即刪除這個小部件也是沒有意義的。 –

+0

你看,這就是我的困惑,因爲我是Python的新手,但知道C++。一個更好的選擇是創建一個手動的'destroyMe'方法,該方法可以徹底刪除對象正在使用的所有東西? – Skitzafreak

回答

1

您可能需要更改代碼中的一些內容。

首先回答您的評論有一個問題:

會是更好的選擇是創建一個越過並刪除對象是手動使用一切人工destroyMe方法?

我們不需要使用pack.forget(),因爲您正在銷燬該框架。

使用容器上的.destroy()方法銷燬該容器中的所有內容。沒有必要一次一個地摧毀所有的東西。您可以在包含多個框架的框架上使用它們,並使用它們自己的一組小部件,並且會破壞主框架內所有框架中的所有內容。或者如果需要,您可以只定位一個小部件。我們不需要。相反,只需在self.destroy()命令後面移動打印語句即可。

看看下面的代碼。它將按照您在問題中發佈的預期順序進行打印,同時在此過程中自行銷燬。

import tkinter as tk 
from tkinter import ttk 


class Frame1(tk.Frame): 

    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent, *args, **kwargs) 
     self.parent = parent 
     self.pack() 
     print("Frame1 created") 
     btn = ttk.Button(self, text = "PRESS", command = self.openFrame2) 
     btn.pack() 

    def openFrame2(self): 
     self.destroy() 
     print("Frame1 destroyed") 
     frame2 = Frame2(root) 


class Frame2(tk.Frame): 

    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent, *args, **kwargs) 
     self.parent = parent 
     self.pack() 
     print("Frame2 created") 
     btn = ttk.Button(self, text = "CLICK", command = self.openFrame1) 
     btn.pack() 

    def openFrame1(self): 
     self.destroy() 
     print("Frame2 destroyed") 
     frame1 = Frame1(root) 


root = tk.Tk() 
frame1 = Frame1(root) 
root.mainloop() 
+0

在'openFrameX()'方法中,爲什麼要將調用'FrameX(self.parent)'的結果賦值給局部變量(當函數返回時立即拋出)? – martineau

+0

這不會導致程序明顯的錯誤行爲 - 只是浪費CPU週期,因爲它沒有完成任何事情。由於'.destroy()'可能會被多次調用,所以在我看來,在派生類中重載它並在那裏調用'print()'會更好。 – martineau

+0

@martineau它只是OP原始代碼的一部分。我甚至沒有看到,因爲我沒有遇到任何錯誤。我想我可以重寫代碼來刪除對象而不是框架。 (固定類型) –