雑食性雑感雑記

知識の整理場。ため込んだ知識をブログ記事として再構築します。

Python のクラスメンバ設定には setattr が便利 (かも)

概要

  • Python のクラスメンバ設定の方法について調べてみた。
  • 引数が増えたときは、dictionary 使った方が良さそう。
  • 引数チェックするのにコード増える⇒効率良く書くには――
    • setattr うまく使うと楽に書ける!!

サンプル概要

  • Pet クラスを作ってみる。メンバは2つ。
    • name : ペットの名前 (string)
    • category : ペットの種類 (string)
  • category ごとの鳴き声を出させる。

(その1) 普通に作る。

  • コンストラクタで普通に設定。引数に連ねて書く。

  • test.py
class Pet1 :
    def __init__(self, name, category) :
        self.name     = name
        self.category = category

    def bark(self) :
        if self.category == 'dog' :
            return "ワンワン"
        if self.category == 'cat' :
            return "にゃー"
        if self.category == 'elephant' :
            return "パオー"

        # others
        return "・・・"

  • メモ
    • 普通の関数と同様、引数でメンバを設定。
    • ○ 一目見て、設定するメンバが分かりやすい。
    • × 今後必要なメンバが増えると引数が増える。

(その2) dictionary で設定

  • dictionary 型の引数で設定する。エラーチェックも付ける。
    • メンバが無ければ「KeyError」を上げる。

  • test.py
class Pet2 :
    def __init__(self, params) :
        if not 'name' in params :
            raise KeyError('name')
        if not 'category' in params :
            raise KeyError('category')
        self.name     = params['name']
        self.category = params['category']

    def bark(self) :
        # 略

  • メモ
    • ○ 必要なメンバが増えても、引数を増やす必要が無い。
    • △ エラーチェックのところ見れば、設定するメンバが分かる。
    • × params の中に存在しない値にアクセスしようとすると落ちる。⇒ エラーチェック必須。
    • × 引数の項目増えるとエラーチェックのコードが増大する。

(その3) dictionary で設定 + setattr を使用。

  • Python の標準関数「setattr」を使用する。

class Pet3 :

    def __init__(self, params) :

        keys = ['name', 'category']

        for key in keys :
            if not key in params :
                raise KeyError(key)
            setattr(self, key, params[key])

    def bark(self) :
        # 略

  • メモ
    • ○ 必要なメンバ増えても、引数を増やす必要が無い。
    • ○ keys 内に必要なメンバを書き込めば、メンバの追加・変更可能。
    • ○ for 文の中でエラーチェックと値の設定行っているので、コード増えない。
    • △ 必要なメンバは (その1) の方が見やすいか…?⇒個々人によるかな。

実際に使ってみる。

  • それぞれ、同じように利用可能。
    • ただし、Pet1 は引数設定、Pet2 と Pet3 は dictionary 型指定。

$ ipython
Python 2.7.5 (default, Jun 17 2014, 18:11:42)
Type "copyright", "credits" or "license" for more information.
( 中略 )

In [1]: from test import Pet1, Pet2, Pet3

In [2]: p1 = Pet1('Pochi', 'dog')

In [3]: print p1.bark()
ワンワン

In [4]: p2 = Pet2({'name': 'Tama', 'category': 'cat'})

In [5]: print p2.bark()
にゃー

In [6]: p3 = Pet3({'name': 'はなこ', 'category': 'elephant'})

In [7]: print p3.bark()
パオー

まとめ

  • 状況に応じて使い分け必要。
  • (その1) と (その3) が使えれば、大体は何とかなるか。な?