🍎
Pythonでclassを使う:getattrとsetattr
getattr,setattrを使う条件を考える
条件X
インスタンスのメンバー変数(下記の例ではparam_name)がプログラムの内部で変数の値のみ判明しているとき(x = 'param_name')を考える。
つまり以下のような例である。
class Model:
def __init__(self,s = 'hoge'):
self.param_name = s
x = 'param_name'
model = Model()
# このときプログラム上でmodelはparam_nameというメンバーを持っていることは知っているが
# ↑変数xに'param_name'が格納されているのはそのため
# プログラムでmodel.param_nameとは書くことはできないとする
まず上記のような条件Xは現実問題で生じるのか疑問に思う方もいるだろう。
結論かなりある。
(例えば任意のclassのメンバー変数の値を参照する関数を考える。
任意のクラスを対象とするので、プログラムを書く人間はメンバー変数名をハードコーディングできない。)
getattr
さて本題条件Xでメンバー変数の値にアクセスすることを考える。
最も直感的な方法はclass.__dict__を使うことである。こちらを用いれば以下のようにして簡単に値を取り出せる。
model.__dict__[x]
次にgetattrを用いると以下のように書ける。
getattr(model,x)
二つの手法を説明したが、オススメはgetattrを使うことであり、__dict__は非推奨である。
その理由は以下である。
- プログラマーとして値を取得するのに
getを使うとわかりやすい(可読性が高い)(Javaとかに精通していればなおさら) - 後述する
setattrと対応が取れる - インスタンスのまま扱えるのに、わざわざクラスを辞書のオブジェクトとして扱う必要がない
setattr
条件Xにおいてmodelのメンバーであるparam_nameを変更することを考える。
変更の仕方は、getattrで用いた上考えを使えば二つ考えられる。
model.__dict__[x] = 'fuga'
setattr(model,x,'fuga')
先ほどの議論と同様、使うべきは後者である。
その他
組み込み関数execを用いればsetattrやgetattrは不要である。
例えば以下のように使う。
exec('model.{x}') #getattrの代わり
exec('model.{x} = 'fuga') #setattrの代わり
だがexecを用いて定義された変数は現状のLinterに無視されてしまう点や、
プログラムの可読性から非推奨である。
Discussion