2017-07-19 15 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() 

このプログラムの目標は簡単です。ボタン付きフレームを含む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は、私がself.destroy()に電話すると__del__メソッドを正しく呼び出すようですが、Frame1は呼び出されません。どうしてこれなの?

+0

Pythonは '__del __()'が呼び出されるかどうか(またはそれがC++ではない)を保証しません。これを行うためにそれを使用しようとすることを忘れて最高です。代わりに、派生クラスで 'destroy()'のオーバーロードについて考えてみてください。 – martineau

+0

FWIW:これは何もしません: 'self.pack_forget'。あなたが正しく呼び出されたとしても( 'self.pack_forget()')、直後にウィジェットを削除するので意味がありません。 –

+0

あなたはそれが私が混乱していることを知っています。なぜなら、私はPythonの新しさですが、C++を知っているからです。より良いオプションは、オブジェクトが手動で使用しているすべてのものを削除し、削除する手動のdestroyMeメソッドを作成することでしょうか? – Skitzafreak

答えて

1

コード内でいくつか変更する必要がある場合があります。

は、あなたがコメントで持っていた質問に答えることはまず:

は、より良いオプションがオーバーになり、オブジェクトを手動で使用しているすべてのものを削除し、手動destroyMeメソッドを作成するだろうか?

を使用する必要はありません。フレームを破棄しているためです。

コンテナ内の.destroy()メソッドを使用すると、そのコンテナ内のすべてのコンテンツが破棄されます。一度にすべてを破壊する必要はありません。独自のウィジェットセットを持つ複数のフレームを含むフレームで使用すると、メインフレーム内のすべてのフレームのすべてが破棄されます。また、必要に応じて単一のウィジェットをターゲットにすることもできます。

第2には__del__は必要ありません。代わりに、self.destroy()コマンドの後にprintステートメントを移動してください。

以下のコードをご覧ください。あなたがあなたの質問に投稿した予想通りの順序で印刷し、その過程でそれ自体を破壊します。

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のオリジナルコードの一部です。私はそれを見ていませんでした。なぜなら、私は誤りに遭遇しなかったからです。私は、フレームの代わりにオブジェクトを削除するコードを書き直すことができると思います。 (固定タイプ) –