初めての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