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
サンクス。
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
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 など
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
ありがとうございます
とてもさんこうになります
カッコのなかは文字じゃないとだめとおもってました