グローバル変数は必要です
Life is beautiful: Python Hack : 噛めば噛むほどおいしくなるクロージャの話クロージャと無名関数を使うと、こんな風に実装することができる。
import yaml def _get_from_disk(): data = open('config.yaml').read().decode('utf8') config = yaml.load(data) # クロージャ内に隠蔽・保持されるローカル変数 global get get = lambda : config # 二回目からはconfigを返す無名関数を呼ぶ様に変更 return get() get = _get_from_disk # 初回のみローダーを実行
いやいや、それはいけません!
このコードは、config.py というモジュールの一部で、
import config #config.get()を使って処理
という使い方を想定していますが、こういう使い方も出来てしまいます。
from config import get as config_get #get()を使って処理
こうすると、config_getの参照先は、config.pyの中でどんな処理をしようと、_get_from_diskのままなので、config_getを呼び出すと毎回ファイルを読み込むことになってしまいます。
同じ問題は、メソッドでも発生します。メソッドオブジェクトを変数に代入した場合です。たとえば、
#!python3 # -*- coding: cp932 -*- class Config: def get(self): self.get = lambda : 1 #2回目以降は1を返すつもり return 0 # 初回のみ0を返すつもり c = Config() get = c.get #メソッドを変数に代入 print(c.get()) # => 0 print(c.get()) # => 1 print(get()) # => 0
というわけで、「初回のみ〜する」場合は、諦めてグローバル変数やメンバ変数を使いましょう。