プロが教えるわが家の防犯対策術!

「Programming Python 4th Edition」(O'REILLY) P.466に
以下のコードを実行すると
本来tmp.set(5)で6番目のRadiobuttonが選択された状態で初回表示されるはずだが
radio1()終了時にtmp.__del__()が呼ばれて
tmpに保持されている値がunsetされることにより
Radiobuttonの初回表示が狂う
(global行のコメントアウトをやめると正しく動作するようになる)
といったことが書いてあり、実際にコードを実行すると確かにそのようになるのですが
tmp.__del__()が呼び出される理由が理解できません。

__del__()が呼び出されるのはオブジェクトへの参照がなくなった時であって
tmpの値(IntVarオブジェクト)はRadiobuttonのコンストラクタに渡されており、Radiobuttonオブジェクト内部で参照され続けるので、__del__()が呼ばれることはないはずだ、と素人考えでは思えるのですが。

お分かりになる方が居らっしゃればどうか教えて下さい。
------------------------------------------------------------
from tkinter import *
root = Tk()

def radio1():
>>>>#global tmp
>>>>tmp = IntVar()
>>>>for i in range(10):
>>>>>>>>rad = Radiobutton(root, text=str(i), value=i, variable=tmp)
>>>>>>>>rad.pack(side=LEFT)
>>>>tmp.set(5)

radio1()
root.mainloop()
(>>>>は空白に読み替えてください)

A 回答 (2件)

tkinter のソースを読んでみるとよくわかると思いますが、


tkinter は Tcl/Tk という言語への橋渡しをしているに過ぎないんですよ。
Python で Tk() とか IntVar() とか書くたびに
それが Tcl の命令に変換されて実行されるだけなんです。

例えば tmp = IntVar() を実行すると、
Tcl 側で PY_VAR1 という変数が作られます。
次に tmp がスコープを抜けると参照がゼロになるので GC が発動します。
その時に tmp.__del__ が呼ばれて Tcl 側にある PY_VAR1 を破棄します。
つまり tmp というのは Tcl 側に存在する変数を管理するオブジェクトなわけです。
そのオブジェクトの破棄イコール Tcl 変数の破棄になっているので
表示がおかしくなるわけです。

ちなみに、

> Radiobuttonのコンストラクタに渡されており、
> Radiobuttonオブジェクト内部で参照され続けるので...

とありますが、Radiobuttonオブジェクトへの参照も
ゼロになっていることを忘れていませんか?
もっとも、Radiobuttonオブジェクトが破棄されても、
Tcl 側のラジオボタンを消すようにはなっていませんが。
    • good
    • 0

結論だけ簡単に書くと、variable=tmp によって tmp の参照数は増えていないので


radio1() を抜けるところで tmp の寿命が尽きると判定されていて、結果 tmp.__del__ が
呼び出されるということになっています。

実装を事細かには書けないのですが、
>Radiobuttonオブジェクト内部で参照され続けるので
この前提が間違っているということです。
    • good
    • 0
この回答へのお礼

ありがとうございます。
参照せずにどうやってRadiobuttonはIntVarの値を読み書きしてるのか想像つかないです。

お礼日時:2011/12/16 19:08

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!