183

次のようなものを書くことができます:

class Test(object):
    def _decorator(self, foo):
        foo()

    @self._decorator
    def bar(self):
        pass

これは失敗します: @self の self が不明です

私も試しました:

@Test._decorator(self)

これも失敗します: テストは不明です

デコレーターのいくつかのインスタンス変数を一時的に変更してから、装飾されたメソッドを実行してから元に戻したいと思います。

4

12 に答える 12

315

このようなものはあなたが必要とすることをしますか?

class Test(object):
    def _decorator(foo):
        def magic( self ) :
            print "start magic"
            foo( self )
            print "end magic"
        return magic

    @_decorator
    def bar( self ) :
        print "normal call"

test = Test()

test.bar()

これにより、デコレーターにアクセスするための self の呼び出しが回避され、通常のメソッドとしてクラスの名前空間に隠されます。

>>> import stackoverflow
>>> test = stackoverflow.Test()
>>> test.bar()
start magic
normal call
end magic
>>> 

コメントで質問に答えるために編集されました:

別のクラスで非表示のデコレータを使用する方法

class Test(object):
    def _decorator(foo):
        def magic( self ) :
            print "start magic"
            foo( self )
            print "end magic"
        return magic

    @_decorator
    def bar( self ) :
        print "normal call"

    _decorator = staticmethod( _decorator )

class TestB( Test ):
    @Test._decorator
    def bar( self ):
        print "override bar in"
        super( TestB, self ).bar()
        print "override bar out"

print "Normal:"
test = Test()
test.bar()
print

print "Inherited:"
b = TestB()
b.bar()
print

出力:

Normal:
start magic
normal call
end magic

Inherited:
start magic
override bar in
start magic
normal call
end magic
override bar out
end magic
于 2009-08-12T01:13:16.843 に答える
61

あなたがやりたいことは不可能です。たとえば、次のコードが有効に見えるかどうかを考えてみましょう。

class Test(object):

    def _decorator(self, foo):
        foo()

    def bar(self):
        pass
    bar = self._decorator(bar)

selfもちろん、その時点で定義されていないため、有効ではありません。Testクラス自体が定義されるまで定義されないため、同じことが言えます(その過程にあります)。このコード スニペットをお見せするのは、これがデコレーター スニペットの変換先だからです。

したがって、ご覧のとおり、デコレーターは、インスタンス化中ではなく、アタッチされている関数/メソッドの定義中に適用されるため、そのようなデコレーターでインスタンスにアクセスすることは実際には不可能です。

クラス レベルのアクセスが必要な場合は、次の方法を試してください。

class Test(object):

    @classmethod
    def _decorator(cls, foo):
        foo()

    def bar(self):
        pass
Test.bar = Test._decorator(Test.bar)
于 2009-08-11T23:33:46.193 に答える
14

これは、同じクラス内で定義された内部selfからアクセスする (そして使用した) 1 つの方法です。decorator

class Thing(object):
    def __init__(self, name):
        self.name = name

    def debug_name(function):
        def debug_wrapper(*args):
            self = args[0]
            print 'self.name = ' + self.name
            print 'running function {}()'.format(function.__name__)
            function(*args)
            print 'self.name = ' + self.name
        return debug_wrapper

    @debug_name
    def set_name(self, new_name):
        self.name = new_name

出力 (でテストPython 2.7.10):

>>> a = Thing('A')
>>> a.name
'A'
>>> a.set_name('B')
self.name = A
running function set_name()
self.name = B
>>> a.name
'B'

上記の例はばかげていますが、機能します。

于 2016-06-07T09:43:25.410 に答える
7

I use this type of decorator in some debugging situations, it allows overriding class properties by decorating, without having to find the calling function.

class myclass(object):
    def __init__(self):
        self.property = "HELLO"

    @adecorator(property="GOODBYE")
    def method(self):
        print self.property

Here is the decorator code

class adecorator (object):
    def __init__ (self, *args, **kwargs):
        # store arguments passed to the decorator
        self.args = args
        self.kwargs = kwargs

    def __call__(self, func):
        def newf(*args, **kwargs):

            #the 'self' for a method function is passed as args[0]
            slf = args[0]

            # replace and store the attributes
            saved = {}
            for k,v in self.kwargs.items():
                if hasattr(slf, k):
                    saved[k] = getattr(slf,k)
                    setattr(slf, k, v)

            # call the method
            ret = func(*args, **kwargs)

            #put things back
            for k,v in saved.items():
                setattr(slf, k, v)

            return ret
        newf.__doc__ = func.__doc__
        return newf 

Note: because I've used a class decorator you'll need to use @adecorator() with the brackets on to decorate functions, even if you don't pass any arguments to the decorator class constructor.

于 2012-08-20T09:13:09.953 に答える
7

非常によく似た問題を調査しているときに、この質問を見つけました。私の解決策は、問題を 2 つの部分に分割することです。まず、クラス メソッドに関連付けるデータをキャプチャする必要があります。この場合、handler_for は Unix コマンドをそのコマンドの出力のハンドラーに関連付けます。

class OutputAnalysis(object):
    "analyze the output of diagnostic commands"
    def handler_for(name):
        "decorator to associate a function with a command"
        def wrapper(func):
            func.handler_for = name
            return func
        return wrapper
    # associate mount_p with 'mount_-p.txt'
    @handler_for('mount -p')
    def mount_p(self, slurped):
        pass

一部のデータを各クラス メソッドに関連付けたので、そのデータを収集してクラス属性に格納する必要があります。

OutputAnalysis.cmd_handler = {}
for value in OutputAnalysis.__dict__.itervalues():
    try:
        OutputAnalysis.cmd_handler[value.handler_for] = value
    except AttributeError:
        pass
于 2012-01-17T17:48:25.580 に答える
3

デコレーターは、一般にインスタンス属性に依存するオブジェクト メソッドの機能よりも、オブジェクト全体(関数オブジェクトを含む)の機能を変更するのに適しているようです。例えば:

def mod_bar(cls):
    # returns modified class

    def decorate(fcn):
        # returns decorated function

        def new_fcn(self):
            print self.start_str
            print fcn(self)
            print self.end_str

        return new_fcn

    cls.bar = decorate(cls.bar)
    return cls

@mod_bar
class Test(object):
    def __init__(self):
        self.start_str = "starting dec"
        self.end_str = "ending dec" 

    def bar(self):
        return "bar"

出力は次のとおりです。

>>> import Test
>>> a = Test()
>>> a.bar()
starting dec
bar
ending dec
于 2013-08-27T02:22:25.257 に答える