データをひとまとめにして扱いたい時、配列やハッシュというデータ型を使う事が出来る。
配列は0から始まる数値で値を管理するため狙った値にアクセスするにはどんな順序で並んでいるかを把握していなければならない。
ハッシュはキーと呼ばれる(主に文字列)もので値を管理するため必ずしもその値の場所を覚えておく必要がない。というよりは逆に順番では覚えられない。
いわばデータにラベルが付いてるような物だ。
例えばaというハッシュがあれば

a = {}
a['name'] = "nioka"
a['age'] = 32
a['position'] = "third"
a['number'] = 23

こんな感じで値を追加していける。 そしてそれらを参照するのも

print a['number']

とか

b = a['position']

と、簡単に扱う事が出来る。
この場合はaという人物データがありそれぞれ'name'や'position'といったその人の属性があるという風に考えられるがPythonはクラスを使って同様の機能を持たせる事が出来る。
例えば

class Person: pass

こんな空っぽのクラスを定義しておいて

a = Person()
a.name = "nioka"
a.age = 32
a.position = "third"
a.number = 23

とする事が出来る。 参照する時も

print a.number

とすればいい。同じクラスから作成したインスタンスでも属性の数や種類を合わせる必要も無い。
Pythonのクラスはそんな(柔軟性があるというよりは)何でもありなクラスなのだ。
とはいえ今のままだと例えば

print a

としても

<__main__.Person instance at 0x66aa8>

と出力されるだけで実際どんな属性がありその値が何なのかがすぐには分からない。 これは以下のような式を書けばとりあえずは解決する

print a.__dict__

もしくは

print vars(a)

とすれば

{'position': 'third', 'age': 32, 'name': 'nioka', 'number': 23}

と、こんな値が出力される。
特殊変数__dict__はオブジェクトaの名前空間を定義しているハッシュ(Pythonだと辞書か)で組み込み関数のvarsは引数に指定したオブジェクトの(同じく名前空間を定義している)辞書を返す関数だ。
これらは辞書を返すので当然ループ処理も出来るしlen()により属性の数を知る事も出来る。

ただこのままだと何となく使いづらいので、先ほどは空っぽだったクラスにあれこれメソッドを追加していきたい。
クラス名をPersonとしている以上は人物に関するデータだという事は想像できるだろう。
となれば、誰でも持っている属性がある。名前や年齢はインスタンス作成時に与える事にしよう。

というわけでまずは__init__メソッドの追加

def __init__(self, name, age):
  self.name = name
  self.age = age

ただしこうした以上はインスタンス作成時には

a = Person("nioka", 32)

と、こうしなければならない。
次は

print a

とした時に表示する文字列を定義するメソッド__str__だ。
これは以下のように定義するだけでいい

def __str__(self):
  return str(self.__dict__)

def __repr__(self):
  return str(self.__dict__)

ここでは類似のメソッド__repr__も追加している。 これで

print a

としたら

{'position': 'third', 'age': 32, 'name': 'nioka', 'number': 23}

の様な出力を得られるようになった。
さらにインスタンスをforループに渡せるようにするには__iter__メソッドを定義すればいい。
こんな感じだ

def __iter__(self):
  return self.__dict__.iteritems()

これで例えば

for k,v in a:
  print "%s => %s" % (k,v)

としたときに

position => third
age => 32
name => nioka
number => 23

こう出力されるようになった。 そして辞書のように扱う事が出来るメソッド__getitem__と__setitem__を追加する

def __getitem__(self, key):
  return self.__dict__[key]

def __setitem__(self, key, value):
  self.__dict__[key] = value

これでこれらの属性に対してまるで辞書のキーに対してアクセスしているように振る舞う事が出来るようになった。
例えば

print a['age']

とか

a['position'] = 'second'

みたいに。

ここまでのクラスは以下のようになっている。

class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def __len__(self):
    return len(self.__dict__)
  def __repr__(self):
    return str(self.__dict__)
  def __str__(self):
    return str(self.__dict__)
  def __iter__(self):
    return self.__dict__.iteritems()
  def __getitem__(self, key):
    return self.__dict__[key]
  def __setitem__(self, key, value):
    self.__dict__[key] = value

あとはそのオブジェクト特有のメソッドをいくらでも追加していけばいい。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/32

コメントする