🍎
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