!!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 "", line 1, in 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 ありがとうございます とてもさんこうになります カッコのなかは文字じゃないとだめとおもってました