19

ほとんどすべてのメソッドがクラスメソッドであるオブジェクト階層があります。次のようになります。

class ParentObject(object):
    def __init__(self):
        pass

    @classmethod
    def smile_warmly(cls, the_method):
        def wrapper(kls, *args, **kwargs):
            print "-smile_warmly - "+kls.__name__
            the_method(*args, **kwargs)
        return wrapper

    @classmethod
    def greetings(cls):
        print "greetings"

class SonObject(ParentObject):
    @classmethod
    def hello_son(cls):
        print "hello son"

    @classmethod
    def goodbye(cls):
        print "goodbye son"

class DaughterObject(ParentObject):
    @classmethod
    def hello_daughter(cls):
        print "hello daughter"

    @classmethod
    def goodbye(cls):
        print "goodbye daughter"

if __name__ == '__main__':
    son = SonObject()
    son.greetings()
    son.hello_son()
    son.goodbye()
    daughter = DaughterObject()
    daughter.greetings()
    daughter.hello_daughter()
    daughter.goodbye()

与えられたコードは以下を出力します:

greetings
hello son
goodbye son
greetings
hello daughter
goodbye daughter

次のコードを出力したいと思います。

-smile_warmly - SonObject
greetings
-smile_warmly - SonObject
hello son
-smile_warmly - SonObject
goodbye son
-smile_warmly - DaughterObject
greetings
-smile_warmly - DaughterObject
hello daughter
-smile_warmly - DaughterObject
goodbye daughter

ただし、各メソッドの前に行を追加したくありません@smile_warmly(上記のコードで追加しようとすると、エラーメッセージが表示されますTypeError: 'classmethod' object is not callable)。むしろ、各メソッドの装飾は、プログラムでメソッド内で行われるようにしたいと思い__init__()ます。

Pythonでメソッドをプログラムで装飾することは可能ですか?

編集:うまくいくように見える何かを見つけました-以下の私の答えを参照してください。BrenBarnに感謝します。

4

2 に答える 2

34

デコレータが行うのは、新しい関数を返すことだけです。これ:

@deco
def foo():
    # blah

これと同じです:

def foo():
    # blah
foo = deco(foo)

@関数を好きなものに置き換えるだけで、構文なしでいつでも同じことを行うことができます。したがって、__init__他の場所で、または他の場所で、すべてのメソッドをループし、それぞれについてそれを。に置き換えることができますsmilewarmly(meth)

ただし、で行うのではなく__init__、クラスの作成時に行う方が理にかなっています。これは、メタクラスを使用して、またはより単純にクラスデコレータを使用して行うことができます。

def smileDeco(func):
    def wrapped(*args, **kw):
        print ":-)"
        func(*args, **kw)
    return classmethod(wrapped)

def makeSmiley(cls):
    for attr, val in cls.__dict__.iteritems():
        if callable(val) and not attr.startswith("__"):
            setattr(cls, attr, smileDeco(val))
    return cls

@makeSmiley
class Foo(object):
    def sayStuff(self):
        print "Blah blah"

>>> Foo().sayStuff()
:-)
Blah blah

この例では、smileDecoデコレータ内にclassmethodデコレーションを配置します。返されるmakeSmileyように入れることもできます。(どちらの方法を実行するかは、smile-decoratorがclassmethodsであるものとどれほど密接にリンクしているかによって異なります。)これは、クラス内で使用する必要がないことを意味します。makeSmileysmileDeco(classmethod(val))@classmethod

また、もちろん、ループ内にmakeSmiley、笑顔の動作でラップするかどうかを決定するロジック(たとえば、メソッドの名前に基づいて)を含めることができます。

@classmethodクラス内で手動で使用する場合は、クラスを介してアクセスされるclassmethodsを呼び出すことができないため、もう少し注意する必要があることに注意してください__dict__。したがって、オブジェクトが呼び出し可能かどうかをチェックするだけでなく、オブジェクトがクラスメソッドオブジェクトであるかどうかを具体的にチェックする必要があります。

于 2012-12-30T23:21:08.630 に答える
1

このソリューションは、私が望む出力を生成します。

class ParentObject(object):
    def __init__(self):
        self._adjust_methods(self.__class__)

    def _adjust_methods(self, cls):
        for attr, val in cls.__dict__.iteritems():
            if callable(val) and not attr.startswith("_"):
                setattr(cls, attr, self._smile_warmly(val))
        bases = cls.__bases__
        for base in bases:
            self._adjust_methods(base)

    def _smile_warmly(self, the_method):
        def _wrapped(self, *args, **kwargs):
            print "-smile_warmly - " +self.__name__
            the_method(self, *args, **kwargs)
        cmethod_wrapped = classmethod(_wrapped)
        # cmethod_wrapped.adjusted = True
        return cmethod_wrapped

    def greetings(self):
        print "greetings"

class SonObject(ParentObject):
    def hello_son(self):
        print "hello son"

    def goodbye(self):
        print "goodbye son"

class DaughterObject(ParentObject):
    def hello_daughter(self):
        print "hello daughter"

    def goodbye(self):
        print "goodbye daughter"

if __name__ == '__main__':
    son = SonObject()
    son.greetings()
    son.hello_son()
    son.goodbye()
    daughter = DaughterObject()
    daughter.greetings()
    daughter.hello_daughter()
    daughter.goodbye()

出力は次のとおりです。

-smile_warmly - SonObject
greetings
-smile_warmly - SonObject
hello son
-smile_warmly - SonObject
goodbye son
-smile_warmly - DaughterObject
greetings
-smile_warmly - DaughterObject
hello daughter
-smile_warmly - DaughterObject
goodbye daughter
于 2012-12-31T02:18:08.700 に答える