2

iResourceというインターフェイスクラスと、それぞれが「request」メソッドを実装するいくつかのサブクラスがあります。リクエスト関数は他のマシンへのソケットI/Oを使用するため、それらを非同期で実行することは理にかなっています。これにより、他のマシンが並行して動作できるようになります。

問題は、iResource.requestを使用してスレッドを開始し、最初の引数としてサブクラスを指定すると、スーパークラスメソッドが呼び出されることです。最初の引数として「type(a).request」と「a」で開始しようとすると、type(a)の値として「」が返されます。それが何を意味するのか、そしてメソッドの真のタイプを取得する方法について何かアイデアはありますか?どういうわけかPythonで抽象メソッドを正式に宣言できますか?

編集:コードを含みます。

def getSocialResults(self, query=''):
    #for a in self.types["social"]: print type(a)
    tasks = [type(a).request for a in self.types["social"]]
    argss = [(a, query, 0) for a in self.types["social"]]

    grabbers = executeChainResults(tasks, argss)

    return igrabber.cycleGrabber(grabbers)

「executeChainResults」は、callableのリスト「tasks」とargs-tuplesのリスト「argss」を取り、それぞれがリストを返すことを前提としています。次に、それぞれを別々のスレッドで実行し、結果のリストを連結します。必要に応じてそのコードを投稿できますが、問題はないので、とりあえず省略します。

オブジェクト「a」は、例外をスローする単一のコンストラクターを持っているため、iResourceタイプではありません。ただし、「type(a).request」を「iResource.request」に置き換えると、基本クラスのメソッドが呼び出されます。さらに、 "self.types ["social "] [0] .request"を呼び出すことは直接正常に機能しますが、上記のコードは次のようになります。 "typeobject'instance'には属性'request'"がありません。

コメントされた行のコメントを解除すると、<type 'instance'>数回印刷されます。

4

2 に答える 2

2

バインドされたメソッド オブジェクト自体を使用できます。

tasks = [a.request for a in self.types["social"]]
#        ^^^^^^^^^
grabbers = executeChainResults(tasks, [(query, 0)] * len(tasks))
#                                     ^^^^^^^^^^^^^^^^^^^^^^^^^

基本クラスを介してメソッドを呼び出すことを主張する場合は、次のようにすることもできます。

from abc import ABCMeta
from functools import wraps

def virtualmethod(method):
    method.__isabstractmethod__ = True
    @wraps(method)
    def wrapper(self, *args, **kwargs):
        return getattr(self, method.__name__)(*args, **kwargs)
    return wrapper

class IBase(object):
    __metaclass__ = ABCMeta
    @virtualmethod
    def my_method(self, x, y):
        pass

class AddImpl(IBase):
    def my_method(self, x, y):
        return x + y

class MulImpl(IBase):
    def my_method(self, x, y):
        return x * y

items = [AddImpl(), MulImpl()]

for each in items:
    print IBase.my_method(each, 3, 4)

b = IBase()  #  <-- crash

結果:

7
12
Traceback (most recent call last):
  File "testvirtual.py", line 30, in <module>
    b = IBase()
TypeError: Can't instantiate abstract class IBase with abstract methods my_method

Python は、たとえば Java のようにインターフェイスをサポートしていません。ただし、abcモジュールを使用すると、特定のメソッドをサブクラスで実装する必要があることを確認できます。通常はabc.abstractmethod()デコレータでこれを行いますが、意図したように、基本クラスを介してサブクラス メソッドを呼び出すことはできませんでした。かつて同様の質問があり、virtualmethod()デコレータのアイデアがありました。とても簡単です。基本的には と同じことをabc.abstratmethod()行いますが、サブクラス メソッドへの呼び出しもリダイレクトします。abcモジュールの仕様はdocsPEP3119にあります。

ところで: Python >= 2.6 を使用していると思います。

于 2012-02-27T03:49:03.210 に答える
1

<type "instance" >Python で「古いスタイルのクラス」を使用しているときに取得する「 」への参照- つまり、「オブジェクト」型階層から派生していないクラス。古いスタイルのクラスは、記述子などを含む、言語の新しい機能のいくつかで動作することは想定されていません。そして、とりわけ、あなたがしていることを使用して、古いスタイルのクラスのクラスから属性 (またはメソッド) を取得することはできません:

>>> class C(object):
...    def c(self): pass
... 
>>> type (c)
<class '__main__.C'>
>>> c = C()
>>> type(c).c
<unbound method C.c>
>>> class D: #not inheriting from object: old style class
...   def d(self): pass
... 
>>> d = D()
>>> type(d).d
>>> type(d)
<type 'instance'>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'instance' has no attribute 'd'
>>> 

したがって、基本クラスが「何もない」のではなく「オブジェクト」から継承するようにして、 type(a) から「リクエスト」メソッドをリクエストしたときにエラーメッセージが表示されるかどうかを確認してください。

あなたの他の観察については、「問題は、iResource.request でスレッドを開始し、最初の引数としてサブクラスを指定すると、スーパークラス メソッドが呼び出されることです。」

それが行う「正しい」ことは、まさに次のことのようです。

>>> class A(object):
...   def b(self):
...     print "super"
... 
>>> class B(A):
...   def b(self):
...     print "child"
... 
>>> b = B()
>>> A.b(b)
super
>>> 

ここでは、クラス "A" のメソッドを呼び出して、特殊化された "A" のインスタンスを指定します。このメソッドは、クラス "A" のメソッドのままです。

于 2012-02-27T04:07:18.637 に答える