4

Guido の multimethod (動的ディスパッチ コード) を変更しようとしています。

http://www.artima.com/weblogs/viewpost.jsp?thread=101605

継承と、場合によっては順不同の引数を処理します。

例 (継承の問題)

class A(object):
  pass

class B(A):
  pass

@multimethod(A,A)
def foo(arg1,arg2):
  print 'works'


foo(A(),A()) #works

foo(A(),B()) #fails

各アイテムの super() が見つかるまで繰り返しチェックするよりも良い方法はありますか?

例 (引数の順序付けの問題) 衝突検出の観点からこれを考えていました。

例えば

foo(Car(),Truck()) and
foo(Truck(), Car()) and

両方をトリガーする必要があります

foo(Car,Truck) # Note: @multimethod(Truck,Car) will throw an exception if @multimethod(Car,Truck) was registered first?

私は特に「エレガントな」ソリューションを探しています。あらゆる可能性を力ずくで切り抜けることができることはわかっていますが、それを避けようとしています。座って解決策を打ち出す前に、いくつかの入力/アイデアを得たかっただけです。

ありがとう

4

2 に答える 2

2

super()親クラスではなくプロキシオブジェクトを返すため(多重継承できるため)、機能しません。を使用isinstance()するのが最善の策ですが、 を使用した辞書検索ほどエレガントにする方法はありませんtype(arg)

別の引数の順序を許可することは良い考えではないと思います。厄介な驚きにつながる可能性があり、継承と互換性があるようにすることは大きな頭痛の種です。ただし、「すべての引数が型 A の場合にこの関数を使用する」または「すべての引数が型 {A, B, E} の場合にこの関数を使用する」ための 2 番目のデコレータを作成するのは非常に簡単です。

于 2011-01-09T20:08:14.053 に答える
2

継承の問題について: これは、MultiMethod を少し変更することで実行できます。(self.typemap を反復処理して で確認issubclass):

registry = {}

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        for typemap_types in self.typemap:
            if all(issubclass(arg_type,known_type)
                   for arg_type,known_type in zip(types,typemap_types)):
                function = self.typemap.get(typemap_types)
                return function(*args)
        raise TypeError("no match")
    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        self.typemap[types] = function

def multimethod(*types):
    def register(function):
        name = function.__name__
        mm = registry.get(name)
        if mm is None:
            mm = registry[name] = MultiMethod(name)
        mm.register(types, function)
        return mm
    return register

class A(object):
  pass

class B(A):
    pass

class C(object):
    pass

@multimethod(A,A)
def foo(arg1,arg2):
  print 'works'


foo(A(),A()) #works

foo(A(),B()) #works

foo(C(),B()) #raises TypeError

self.typemapはdictであり、dictは順序付けられていないことに注意してください。したがって、@multimethod を使用して 2 つの関数を登録し、一方の型が他方のサブクラスである場合、の動作はfoo未定義になる可能性があります。つまり、結果はtypemap_typesループ内でどちらが最初に現れるかによって異なりますfor typemap_types in self.typemap

于 2011-01-09T20:08:16.433 に答える