🍎

Pythonでclassを使う:getattrとsetattr

2022/12/10に公開

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を用いればsetattrgetattrは不要である。

例えば以下のように使う。


exec('model.{x}') #getattrの代わり
exec('model.{x} = 'fuga') #setattrの代わり

だがexecを用いて定義された変数は現状のLinterに無視されてしまう点や、
プログラムの可読性から非推奨である。

Discussion