#Pythonのグローバル変数
Pythonを使っていると、モジュール間共通のグローバル変数を使いたくなるシーンがあります。
このグローバル変数がとても扱いにくく
関数内からグローバル変数を書き換える場合、
使用前にglobalで変数を宣言しなければいけません。
global val1
def func1():
global val1
val1 = 100
def main():
global val1
func1()
print(val1)
扱う変数の量が増えると、行頭のglobal宣言だけで数行埋まってしまいます。
プログラムをクラス化すれば良いのですが、Pythonではクラス変数の前にself.をつけなければいけないという制約があるため、コードが冗長になってしまいます。
また、モジュール外から他のモジュールのグローバル変数にアクセスしようとしても、思うようにいきません。
def func1():
global val1
val1 = 100
from my_function import *
global val1
def main():
func1()
print(val1)
このように書いてもグローバル変数を別モジュールから書き換えることが出来ません。
#共通のファイルをインポートしてas gとする
これらの問題を解決する、とっておきの方法を思いつきました。
global_value.pyという中身空っぽのファイルを作成します(名前は何でも良いです)
#中身は空っぽ
使う側で、それをgとしてimportします
そして、グローバル変数をg.val1のように使用します。
import global_value as g
def func1():
g.val1 = 1
import my_function
import global_value as g
def main():
func1()
print(g.val1)
こうすることでglobalの宣言は一切必要なくなり
g.をつけた変数はグローバル変数として扱えるようになります。
この変数は、他のモジュールからでも、クラス内からでも自由にアクセスできます。
変数名はやや冗長になりますが、ローカルとグローバルを明示する前置詞として働くため、プラスの効果も大きいと思います。
#グローバル変数のメリット
Pythonはスクリプト言語です。
スクリプト言語は遅いだの、レベルが低いだの難癖を付けられがちですが
他の言語にはない強力な機能が用意されています。
それが、文字列をコードとして扱えるeval関数とexec関数です。
exec("g.val=100")
とすれば、g.valの値を100に書き換えることが出来ます。
これがtkinterと変数の同期処理で輝きます。
tkinterウィジェットを管理する辞書のキー値に変数名を用いることで決まったループ処理1つで変数とGUIの同期ができます。
widgets = dict()
widgets["g.val1"] = widget1
widgets["g.val2"] = widget2
widgets["g.val3"] = widget3
def UpdateValue():
for key in widgets.keys():
exec(key+"="+str(widgets[key].data.get()))
実際はウィジェットクラスに適切な文字列を返すget_data_textメソッドを用意したほうが良いです。
この壁になっていたのが、グローバル変数問題でした。
どうにかしてウィジェットクラス内部から、メインプログラムのグローバル変数を書き換えられないかと悩んでいたら、この方法を思いつきました。
これが、誰かのお役に立てば幸いです。