過去のスレッドのダイジェスト版
Pythonのお勉強
part17
委譲(デリゲート)での__getattribute__の使い方が分りません。(19-39)
19 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 01:54:54
委譲(デリゲート)での__getattribute__の使い方が分りません。
従来の__getattr__() は、解決できない属性名の時だけ呼ばれるが
__getattribute__() は、属性値の取得が必要になったときに、常に呼ばれるらしいのですが。
まず、__getattr__でのサンプル。
class wrapper(object):
def __init__(self, obj):
self.__wrapped = obj # obj を組み込む。
def __getattr__(self, attrname): # attrnameは、知らない名前の属性が来たら呼び出される
return getattr(self.__wrapped, attrname) # 組み込まれたオブジェクトにgetattr 関数で処理を委託。
l = wrapper([]) # リストを引数にwrapper クラスを呼び出すと、リストにできる操作なら全てできる
(実行すると、正しく動作します)
>>> l.append(333)
>>> l.pop(0)
333
20 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 01:56:08
ここで、__getattr__を__getattribute__に置き換えます。
class wrapper(object):
def __init__(self, obj):
self.__wrapped = obj # obj を組み込む。
def __getattribute__(self, attrname):
return getattr(self.__wrapped, attrname)
l = wrapper([])
(試しに、実行してみます)
>>> l.append(333)
(ここで暴走)
なぜ暴走するのかよく分りません。
__getattribute__はどう使うのが正しいのでしょうか?
21 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 02:48:11
>>20
self.__getattribute__ の中で self._wrapped を取得しようとすると
さらに self.__getattribute__(self, '_wrapped') を呼び出して無限再帰ループになるみたい。
解決方法は・・・たとえば、_wrapped をインスタンス属性としてもつんじゃなくて
クラス属性にインスタンスをキーにした辞書をもつようにするとかでどう?
class wrapper(object):
_wrapped = {}
def __init__(self, obj):
wrapper._wrapped[hash(self)] = obj
def __del__(self):
del wrapper._wrapped[hash(self)]
def __getattribute__(self, attrname):
return getattr(wrapper._wrapped[hash(self)], attrname)
23 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 03:00:57 __getattr__ を __getattribute__ に置き換えるって話じゃないのか
24 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 03:08:57 if attrname not in ['_wrapped', etc, etc]: return getattr(self._wrapped, attrname) else: super(wrapper, self).__getattribute(attrname)
25 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 03:14:55
>>21 でおkかと思ったけど、len() ができないなぁ。
>>> l = wrapper([])
>>> len(l)
Traceback (most recent call last):
File "<pyshell#84>", line 1, in <module>
len(l)
TypeError: object of type 'wrapper' has no len()
TypeError なあたり、決まった型にしか呼べないのかも。
len(x) って内部で x.__len__ を返してるのかと思ってたけど、ちょっと違うのかな。
>>> l.append(3)
>>> l.__len__()
1
27 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 04:03:11
>>25
アクセサでフィールド値を取得してから、len しないとダメじゃない?
__getattribute__ じゃなく、__getattr__ の例で悪いけど、
この場合、同じと思う。
class wrapper(object):
def __init__(self, obj):
self.__wrapped = obj
def __getattr__(self, attrname):
return getattr(self.__wrapped, attrname)
def get_wrapped(self): # フィールド値取得メソッドを設定
return self.__wrapped
l = wrapper([])
l.append(333)
(ここで len を実行。正常に動作する)
>>> len(l.get_wrapped())
1
>>>
28 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 04:37:24 >>25 __getattribute__ でフックされるのは、dir(l) で出てくるものだけだと思う。 したがって、lenは使えないが__len__は使えるということになる。 >>> dir(l) ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>>
30 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 04:50:46 >>28 なるほど。__len__ が特別だったのか。確かに __init__ とかフックされたら困るよなぁ。 __len__ を定義して、ラップしているオブジェクトの len() を返すようにしたら、ちゃんと動きますた。 質問主じゃないけど勉強になった。この先 __getattribute__ を使うかどうかはともかくとしてw
35 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 12:43:37 >>19 >>20 で __getattribute__ の使い方について質問した者です。 なぜ、__getattr__ ではなく__getattribute__ を使いたいと思ったかというと、 「スーパークラスの配列で,複数の異なるサブクラスのインスタンスを一元管理する」 というテクニックを使えるようにしておきたいと思ったからです。 ちなみに、従来からあるメソッド __getattr__() は、解決できない属性名の時だけ呼ばれるが __getattribute__() は、属性値の取得が必要になったときに、常に呼ばれる、とのこと。 「スーパークラスの配列で,複数の異なるサブクラスのインスタンスを一元管理する」に ついては、javaの解説ページですが、下のところにあります。 http://itpro.nikkeibp.co.jp/members/NSW/ITBASIC/20050620/162997/ (略)部長さん,課長さん,担当さんをそれぞれ表すBuchoクラス,Kachoクラス,Tantoクラスを 定義し,それぞれのクラスのメンバーとして給与の金額を返すgetKyuyoという関数があるとします。 複数のクラスに同じ名前の関数があるのですから,それらを汎化して社員を表すShainクラスを定義 しましょう。(略) サブクラスであるBuchoクラス,Kachoクラス,Tantoクラスは,0を返すgetKyuyoを継承することに なります。こんな関数を継承しても役に立ちませんね。スーパークラスから継承した関数の機能が サブクラスに合わない場合は,サブクラスで同名のメソッドを記述すれば上書き変更できます。 これを「オーバーライド(override)」と呼びます。部長さんの給与は70万円,課長さんの給与は 50万円,担当さんの給与は30万円としましょう (略)汎化を行わなかったら「役職ごとに給与を求めて集計する」という手順になるでしょう。 汎化を行ったことで「社員の給与を一気に集計する」という手順が実現できるのです。(終) まあ、それに必要かなと思ったんですが、単にshain = [] に shain.append(shainObject)で集めて、 for で 要素に次々と .getKyuyo して、それを加算していくだけでいいような気もします。 本当に __getattribute__ が使えないと困るのかな? 頭冷やして考えないと分からないw とにかく、いろいろ参考になりました。みなさん、どうもありがとう。
37 名前:デフォルトの名無しさん 投稿日:2007/02/18(日) 14:06:03
>>35
そのプログラムは単にオブジェクト指向のポリモーフィズム(多様性)を利用しているだけなので
__getattribute__ は必要ありません。そのプログラムを Python で書くなら、こんな感
じになります。
class Shain:
def getKyuyo(self): return 0
class Bucho(Shain):
def getKyuyo(self): return 700000
class Kacho(Shain):
def getKyuyo(self): return 500000
class Tanto(Shain):
def getKyuyo(self): return 300000
s = [ Bucho(), Kacho(), Kacho(), Tanto(), Tanto(), Tanto() ]
goukei = 0
for p in s: goukei += p.getKyuyo()
print goukei
ちなみに、Python では Bucho Kacho Tanto を Shain のサブクラスにしなくても動きます。
これは Java の「変数の型」という概念が Python にはないからです。
Python ではオブジェクトに対してメソッドを呼び出した場合、その名前を持つメソッドが
動的に(実行時に)決定されるので、スーパークラスで抽象化する必要はありません。(ダックタイピング)
(ただし、スーパークラスの振る舞いを引き継ぐ為の継承は有効な手段です)
呼び出されるメソッドが静的に(コンパイル時に)決定される Java や C++ などとの大きな違いですね。
39 名前:35 投稿日:2007/02/18(日) 14:26:56 >>37 サンクス。
a=1.2+1.0000000000000000ってやると... (875-879)
875 名前:デフォルトの名無しさん 投稿日:2007/04/03(火) 01:34:43 a=1.2 a=1.2+1.0000000000000000 ってやるとaが 2.2000000000000002 になって困ってます どうやったら解決しますか?
876 名前:デフォルトの名無しさん 投稿日:2007/04/03(火) 01:39:54
>>> from decimal import Decimal
>>> Decimal('1.2') + Decimal('1.0000000000000000')
Decimal("2.2000000000000000")
878 名前:デフォルトの名無しさん 投稿日:2007/04/03(火) 02:17:09 ありがとうございます
879 名前:デフォルトの名無しさん 投稿日:2007/04/03(火) 08:02:41 ほんとにぱいそん信者は使えないねw
チミ達はIDEというかエディターなどというものはなに使ってる (915-922)
915 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 18:35:18 チミ達はIDEというかエディターなどというものはなに使ってる まさかメモ帳はありえないだろ普通wwww おれはsciteを使ってます
916 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 19:05:00 vim-7
917 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 19:10:29 xyzzy
918 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 19:21:39 IDLE
919 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 20:45:08 emacs five-things-I-hate ってちゃんと使ってないと怖くて書けないよな‥
920 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 21:06:43 PyScripter + IDLE
921 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 21:18:10 秀丸
922 名前:デフォルトの名無しさん 投稿日:2007/04/05(木) 23:21:04 秀丸 たまに PyCrust 併用 最終確認が必要な場合は eclipse など
intをfloatにするほうほうがわかりません (931-933)
931 名前:デフォルトの名無しさん 投稿日:2007/04/06(金) 21:57:30 intをfloatにするほうほうがわかりません
932 名前:デフォルトの名無しさん 投稿日:2007/04/06(金) 22:05:59 >>>float(4) 4.0
933 名前:デフォルトの名無しさん 投稿日:2007/04/06(金) 22:09:14 ありがとうございます とてもさんこうになります カッコのなかは文字じゃないとだめとおもってました
part18
docutilsをライブラリとして使う方法を探しています。(16-19)
16 名前:デフォルトの名無しさん 投稿日:2007/04/10(火) 17:35:11 docutilsをライブラリとして使う方法を探しています。 s = """ * foo * bar * baz """ html = rst2html(s) print html, としたら <ul> <li>foo</li> <li>bar</li> <li>baz</li> </ul> に変換されるようにしたいんです。 http://docutils.sourceforge.net/ をみてもいまいち分からないのですが、アドバイスお願いします。
17 名前:デフォルトの名無しさん 投稿日:2007/04/10(火) 19:17:57
import docutils.core
src = """\
* foo
* bar
* baz
"""
settings = {
"stylesheet": "",
"stylesheet_path": None,
}
print docutils.core.publish_string(src, writer_name='html',
settings_overrides=settings)
18 名前:デフォルトの名無しさん 投稿日:2007/04/10(火) 19:27:10 >>17 ありがとうございます
19 名前:デフォルトの名無しさん 投稿日:2007/04/10(火) 19:37:16 1. docutilsをライブラリとして使う、ねえ。まず rst2html.py が何してるか見てみますか。 2. docutils.core.publish_cmdline() とゆー関数を呼んでるなあ。どういう関数かな。(site-packages/docutils/core.py を見る) 3. publish_なんちゃら という関数がいっぱいあるなあ。お、publish_string とゆー関数もあるなあ。 4. 使い方がよく分からないから docutils.core.publish_string でググってみよう。(用例が見つかる) 5. publish_string にはたくさん引数があるなあ。writer_name は rst2html.py で指定されてるのと同じ値を渡してみよう。 6. スタイルシートファイルが無いって怒られるなあ。デフォルトの値だとマズいんだろうなあ。 7. settings_overrides とゆー引数の値にテキトーな辞書を指定すればデフォルトを上書き指定できるんだろうなあ。 8. rst2html.py のコマンドラインオプションに --stylesheet-path とゆーのがあるから "stylesheet_path" を辞書のキーにしてみよう。(ビンゴ!) 9. とりあえずスタイルシートファイルは要らないなあ。値は None にしてみよう。 というような調子で試行錯誤した結果が>>17のコード。 要約すると「ソース嫁」「ググれ」。
- スレッドダイジェスト版のようなものを作成テスト - 名無しさん (2007年04月12日 07時27分25秒)
- 1ページが大きすぎると編集しづらいので、part Nごとに分けてページを作成して、あとから、includeで1ページにまとめた方がいいかもしれない - 名無しさん (2007年04月12日 07時43分16秒)