3

オプションで他のクラスに追加できるようにしたいメソッドを持ついくつかのクラスがあります。私の最初の解決策はミックスインを使用することでしたが、これは少し見苦しくなります:

class Schedule(Enumerator, Humanizer, Inferer, ...):
    ...

そこで、クラス デコレータを使用して同じ効果を実現できるのではないかと考えました。

@enumerator
@humanizer
@inferer
class Schedule(object):
    ...

デコレータ関数のサンプルは次のとおりです。

import inspect

def inferer(original_class):
    from myproj.lib.inferer import Inferer
    methods = inspect.getmembers(Inferer, predicate=inspect.ismethod)
    for method in methods:
        setattr(original_class, method[0], types.MethodTypes(method[1], original_class))
    return original_class

...装飾されたクラスにメソッドとクラスメソッドを適切に追加するようです。ただし、これらの追加されたメソッド (またはクラスメソッド) のいずれかを装飾されたクラスで呼び出すと、いくつかのエラーが発生します。

メソッドの場合:

>>> Schedule().humanize()
TypeError: unbound method humanize() must be called with Humanizer instance as first argument (got type instance instead)

...これらがクラスメソッドとして追加されていることを示しているように見えるのはどれですか?

クラスメソッドの場合:

>>> schedule = Schedule.infer(foo)
TypeError: infer() takes exactly 2 arguments (3 given)

infer の定義に注意してください。

class Inferer(object):
    @classmethod
    def infer(cls, dates):
        ...

inferとして呼び出されたときに取得する引数を示すために、いくつかの行を追加しましたSchedule.infer()

cls: <class 'myproj.lib.inferer.Inferer'>
dates: <class 'myproj.Schedule'>

だから、私の質問:

これらの追加されたメソッドとクラスメソッドが奇妙な動作をする原因となるデコレータ関数の何が問題になっているのでしょうか? または、これらの追加を適切に処理するためにデコレータ関数を変更する方法を教えてください。

任意の点について明確にすることができるかどうか教えてください。

4

1 に答える 1

4

これは良い考えだったとしましょう。これは、それを達成するための 1 つの方法です。アドバイスできるとは言えませんが。

def horrible_class_decorator_factory(mixin):
    def decorator(cls):
        d = cls.__dict__.copy()
        bases = tuple([b for b in cls.__bases__ if b != object] + [mixin])
        return type(cls.__name__, bases, d)
    return decorator

これで、次のようなことができます。

class Inferer(object):
    @classmethod
    def foo(cls):
        return "bar" + cls.__name__

inferer = horrible_class_decorator_factory(Inferer)

@inferer
class X(object):
    pass

X.foo()
"barX"

私はこれについてのコメント者と一緒です。何かができるからといって、そうしなければならないわけではありません。

于 2012-11-12T00:09:17.513 に答える