質問: EditBox4.get() print(i1) print(i4) import 次のモジュール ``` エディットボックスには初期値が入っておりますが、メイン.pyでは、記入された値を変数へgetできておりました。 しかし、次のモジュールで、 次のモジュール.py ``` from メイン import i1 from メイン import i2 from メイン import i3 from メイン import i4 print(i1) print(i2) print(i3) print(i4) ``` としたときに、i1~i4は初期値のエディットボックスの値を読み取っております。 どのようにしたらいいでしょうか。
回答: ご自分で書いておられますが・・・ あるモジュールMにある属性V(変数だったり関数だったりクラスだったりします)をimportするとimportした時点での属性Vの属性値が取り込まれます。import後にM上で属性Vの値が変化してもimportをした側のモジュールの属性Vの値は古いままです。 要するにimportは「属性名とその値の束縛状態を取り組む」のではなく「単にimportした時点での属性名とその値を自モジュールの属性としてコピーするだけ」のものです。 それゆえimportするなら「後から変化しない(※)ような値を持つ属性」を取り組むべきであって後から変化するようなものをimportしてもしかたないといえます。 ※: 後から変化しない Pythonでは一部例外を除いてやろうと思えばどんな属性値でもいくらでも変更できます。関数やクラスとして定義した名前は単なる属性名なのでその属性名に後からいくらでも「違う値」を設定しなおせます。ということでここでいう「後から変化しない」とは「プログラマーが後から変更するつもりがないもの」というほどの意味です。 EditBox1.get()した結果を設定した変数i1などは「プログラムの実行に応じて変化し得る値」と言えましょう。なので普通i1をimportしたりはしません。importすべきなのはEditbox1です。正確にはわかりませんが、おそらくEditbox1はプログラムの実行が進んでも変わるようなものではないと思います。こちらをimportしておけばimportした先のモジュールでEditBox1.get()とやって望む値を得ることができます。 ちなみにEditBox1とかEditBox2という名前をimportするのは「いつでもそれが最適」とは限りません。importするなら最小限の名前集合にした方がよいという考え方もあるでしょう。 panel.py ``` import tkinter as tk editbox1 = tk.Entry(...) editbox2 = tk.Entry(...) ... ``` main.py ``` # あまりよくないと思う例 from panel import editbox1, editbox2, ... def xxx(): i1 = editbox1.get() i2 = editbox2.get() ... # こちらでよいのでは? import panel def xxx(): i1 = panel.editbox1.get() i2 = panel.editbox1.get() ... ``` panel.editbox1.get() より editbox1.get() の方が「短い記述だからよいではないか」と思われるかも知れません。確かにそうですが短い名前でアクセスできるというのも善し悪しです。大きなプログラムを作るにつれ「直接名前をトップレベルにごちゃごちゃと取り込むことは悪手」になってきます。プログラムが複雑になればなるほど最小限の名前(究極的にはモジュール名だけ)をimportし、そのモジュール配下の様々な属性を「importした名前.属性名」としてアクセスできた方が名前の衝突の心配を最小限にできるため安心して設計できる気がします。 Pythonではビルトインのクラス名や関数名も全て上書きできてしまいますのでid, str, int等々の名前は「モジュールのトップレベルの名前やローカル変数名にしないほうがよい」のですが、「何かのオブジェクトの属性名としてならいくらでも自由に使える」ということに目を向けるとよいと思います。 ``` from other import id a = id # よくない import other a = other.id # これなら安心 ```