初めてのPython(25章後編)

getattr(X, N)

Xに所属するNという属性を返す関数。
X.Nとの違いは、getattrではNに”文字列を返す式"を使うこと。
文字列を返す式の1つがNに変数を渡すこと

X.__dict__[N]との違いは、getattrでは上位クラスの属性の検索が行われること。

[kobakoba0723@fedora13-intel64 ~]$ python
Python 2.6.4 (r264:75706, Apr  1 2010, 02:55:51) 
[GCC 4.4.3 20100226 (Red Hat 4.4.3-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class C1(object):
...   def hoge(self):
...     self.data1 = 'hoge'
... 
>>> class C2(C1):
...   def piyo(self):
...     self.data2 = 'piyo'
... 
>>> X = C2()
>>> X.piyo()
>>> X.hoge()
>>> X.__dict__
{'data1': 'hoge', 'data2': 'piyo'}
>>> getattr(X, 'hoge')
<bound method C2.hoge of <__main__.C2 object at 0x7f71cadbbed0>>
>>> getattr(X, 'piyo')
<bound method C2.piyo of <__main__.C2 object at 0x7f71cadbbed0>>
>>> C2.__dict__.keys()
['__module__', 'piyo', '__doc__']
>>> C1.__dict__.keys()
['__dict__', '__module__', '__weakref__', '__doc__', 'hoge']
>>> getattr(C2, 'hoge')
<unbound method C2.hoge>
>>> X.hoge
<bound method C2.hoge of <__main__.C2 object at 0x7f71cadbbed0>>
>>> 

ただ、Xにインスタンスを指定すると、__dict__の出力に'piyo'メソッドが出てこない。
なんでだろう。。。piyoメソッドはC2のクラスメソッドだからか。。。クラス属性は出てこないってことか。
名前空間というか、属性の管理はよくわかってないなぁ。

[kobakoba0723@fedora13-intel64 ~]$ python
Python 2.6.4 (r264:75706, Apr  1 2010, 02:55:51) 
[GCC 4.4.3 20100226 (Red Hat 4.4.3-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class C1(object):
...   c_data = 'C1'
...   def __init__(self, data):
...     self.i_data = data
...   def hoge(self):
...     self.hoge = 'hoge'
... 
>>> X = C1('test')
>>> X.__dict__
{'i_data': 'test'}
>>> getattr(X, 'c_data')
'C1'
>>> getattr(X, 'hoge')
<bound method C1.hoge of <__main__.C1 object at 0x7f6e7d16ef10>>
>>> 

結合メソッドと非結合メソッド

Cをクラス、Iをインスタンス、Mをメソッドをすると
C.Mが非結合メソッドで、I.Mが結合メソッド。
上の出力例では、

出力例 メソッドの種類
getattr(C2, 'hoge') 非結合メソッド
X.hoge 結合メソッド

非結合メソッドを利用して結合メソッドと同様のことをするには、
C.M(I)というようにインスタンスを引数にして呼び出す。
このやり方はスーパークラスの__init__を呼び出すときに使う方法。

ファクトリ

引数に指定されたオブジェクトを呼び出す関数。
apply(objName, arg1, ...) や objName(arg1, ...)

[kobakoba0723@fedora13-intel64 ~]$ cat factory.py 
#!/usr/bin/env python

def factory(obj, *args):
  return apply(obj, args)

class Person(object):
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def __repr__(self):
    return '<Person: name=%s, age=%s>' % (self.name, self.age)

class Product(object):
  def __init__(self, name, price, func):
    self.name = name
    self.price = price
    self.func = func
  def __repr__(self):
    return '<Product: name=%s, price=%s, func=%s>' % (self.name, self.price, self.func)

def add_obj(x, y):
  return x + y

if __name__ == '__main__':
  taro = factory(Person, 'taro', 28)
  spam = factory(Product, 'spam', 200, 'Spicied Ham')
  num = factory(add_obj, 1, 2)
  array = factory(add_obj, [1, 2], [3, 4])
  
  print 'type<taro>:', type(taro)
  print taro
  print 'type<spam>:', type(spam)
  print spam
  print 'type<num>:', type(num)
  print num
  print 'type<array>:', type(array)
  print array

[kobakoba0723@fedora13-intel64 ~]$ python factory.py 
type<taro>: <class '__main__.Person'>
<Person: name=taro, age=28>
type<spam>: <class '__main__.Product'>
<Product: name=spam, price=200, func=Spicied Ham>
type<num>: <type 'int'>
3
type<array>: <type 'list'>
[1, 2, 3, 4]
[kobakoba0723@fedora13-intel64 ~]$ 

apply(obj, args) よりも obj(args) のほうが好ましいらしい。
apply関数を間に挟まないから判りやすいといえば判りやすいけど、それだけじゃないんだろうな。
あと、factory関数自体の定義にも、キーワード引数を受け付けられるように

def factory(obj, *arg, **kwargs):
  obj(arg, kwargs)

とかにすると対応できる範囲がなお広がるらしい。

その他

3/6に 駿府ラソン 10km をなんとか完走。
目標のうち無理目だった 5分/km には到底届かない 53:53 だったけど、
初マラソン 55分 (5分半/km) を切るっていう目標は達成できた。
来年ハーフでエントリーするか、10kmでリベンジか悩み中。ハーフを走ってみたいってのが今のところは強い。


走り終わって思ったのは2つ。
ちゃんとコースを把握してなかったのが悪いんだけど、ラスト2kmの駿府城のまわり1周はつらかった。
門が見えるたびに、「ここで入れるんかな?」って思ってたら最後の最後の門まで入れんし。
ちゃんとコースを把握しときなさいってことやね。

あと、折り返しまでが団子状態で自分のペースで走れんからって隙間を縫うようにしてたら、
ストップandゴーに近い感じになっちゃって最後の方にきてかなりダメージが。
調子こいたらあかんってことかも、身の程を知りなさいってことか。


次は、4/17の掛川・新茶マラソン 10km。
ここでは駿府ラソン以上の記録を最低限出すのと、1分縮められたらなと思う*1
フルマラソンのコースはアップダウンがかなりきついみたいだけど、
10kmは構内周回コースみたいだから、なんとか目標達成したいなぁ*2

*1:4分短縮はさすがにつらそう、24秒/kmだしなぁ

*2:開けてびっくり玉手箱とかならんように