トップ
Team(・∀・)2ch
新規
一覧
検索
ヘルプ
RSS
ログイン
Part17の編集
!!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 ありがとうございます とてもさんこうになります カッコのなかは文字じゃないとだめとおもってました
タイムスタンプを更新しない
スパムではありません(必ずチェックして下さい)
添付ファイル
[
ヘルプ
]
メニュー
トップ
Pythonの紹介
FAQ
質問の仕方
参考図書
参考サイト
翻訳文献
日本語
問題集
よくある誤解
Python可能サーバ
Pythonの更新情報
処理系
開発環境
2chテンプレ
過去ログ
練習用ページ
雑談
公式サイト
本家オフィシャル
日本ユーザー会
検索
キーワード
AND
OR
ページ内容も含める
編集用
FrontPage
InterWikiName
Keyword
Menu
PluginHelp
更新履歴
2022/11/16
鐃緒申鐃所集
2022/10/11
japaneseCharset
2022/9/24
Implementations
2021/8/26
雑談
2020/12/11
%CC%E4%C2%EA%BD%B8