问题:类中的Python装饰器
可以这样写吗:
class Test(object):
    def _decorator(self, foo):
        foo()
    @self._decorator
    def bar(self):
        pass这将失败:@self中的self未知
我也尝试过:
@Test._decorator(self)也会失败:测试未知
我想在装饰器中临时更改一些实例变量,然后运行装饰的方法,然后再将其更改回。
回答 0
这样的事情会满足您的需求吗?
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回答 1
您想做的事是不可能的。例如,下面的代码是否有效:
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)回答 2
import functools
class Example:
    def wrapper(func):
        @functools.wraps(func)
        def wrap(self, *args, **kwargs):
            print("inside wrap")
            return func(self, *args, **kwargs)
        return wrap
    @wrapper
    def method(self):
        print("METHOD")
    wrapper = staticmethod(wrapper)
e = Example()
e.method()回答 3
我在某些调试情况下使用这种类型的装饰器,它允许通过装饰来覆盖类属性,而无需找到调用函数。
class myclass(object):
    def __init__(self):
        self.property = "HELLO"
    @adecorator(property="GOODBYE")
    def method(self):
        print self.property这是装饰代码
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 注意:因为我使用了类装饰器,所以即使您没有将任何参数传递给装饰器类构造函数,也需要使用@adecorator()放在方括号中来装饰函数。
回答 4
这是self从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'上面的示例很愚蠢,但是可以。
回答 5
我在研究一个非常相似的问题时发现了这个问题。我的解决方案是将问题分为两部分。首先,您需要捕获要与类方法关联的数据。在这种情况下,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现在,我们已将某些数据与每个类方法相关联,我们需要收集该数据并将其存储在class属性中。
OutputAnalysis.cmd_handler = {}
for value in OutputAnalysis.__dict__.itervalues():
    try:
        OutputAnalysis.cmd_handler[value.handler_for] = value
    except AttributeError:
        pass回答 6
这是迈克尔·斯佩尔(Michael Speer)的答案的扩展,以进一步采取一些措施:
一个实例方法装饰器,它接受参数并通过参数和返回值作用于函数。
class Test(object):
    "Prints if x == y. Throws an error otherwise."
    def __init__(self, x):
        self.x = x
    def _outer_decorator(y):
        def _decorator(foo):
            def magic(self, *args, **kwargs) :
                print("start magic")
                if self.x == y:
                    return foo(self, *args, **kwargs)
                else:
                    raise ValueError("x ({}) != y ({})".format(self.x, y))
                print("end magic")
            return magic
        return _decorator
    @_outer_decorator(y=3)
    def bar(self, *args, **kwargs) :
        print("normal call")
        print("args: {}".format(args))
        print("kwargs: {}".format(kwargs))
        return 27然后
In [2]:
    test = Test(3)
    test.bar(
        13,
        'Test',
        q=9,
        lollipop=[1,2,3]
    )
    
    start magic
    normal call
    args: (13, 'Test')
    kwargs: {'q': 9, 'lollipop': [1, 2, 3]}
Out[2]:
    27
In [3]:
    test = Test(4)
    test.bar(
        13,
        'Test',
        q=9,
        lollipop=[1,2,3]
    )
    
    start magic
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-3-576146b3d37e> in <module>()
          4     'Test',
          5     q=9,
    ----> 6     lollipop=[1,2,3]
          7 )
    <ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs)
         11                     return foo(self, *args, **kwargs)
         12                 else:
    ---> 13                     raise ValueError("x ({}) != y ({})".format(self.x, y))
         14                 print("end magic")
         15             return magic
    ValueError: x (4) != y (3)回答 7
装饰器似乎更适合于修改整个对象(包括函数对象)的功能,而不是通常取决于实例属性的对象方法的功能。例如:
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回答 8
您可以装饰装饰器:
import decorator
class Test(object):
    @decorator.decorator
    def _decorator(foo, self):
        foo(self)
    @_decorator
    def bar(self):
        pass回答 9
我有一个可以帮助的装饰器实施
    import functools
    import datetime
    class Decorator(object):
        def __init__(self):
            pass
        def execution_time(func):
            @functools.wraps(func)
            def wrap(self, *args, **kwargs):
                """ Wrapper Function """
                start = datetime.datetime.now()
                Tem = func(self, *args, **kwargs)
                end = datetime.datetime.now()
                print("Exection Time:{}".format(end-start))
                return Tem
            return wrap
    class Test(Decorator):
        def __init__(self):
            self._MethodName = Test.funca.__name__
        @Decorator.execution_time
        def funca(self):
            print("Running Function : {}".format(self._MethodName))
            return True
    if __name__ == "__main__":
        obj = Test()
        data = obj.funca()
        print(data)回答 10
在内部阶级中宣布。此解决方案非常可靠,建议使用。
class Test(object):
    class Decorators(object):
    @staticmethod
    def decorator(foo):
        def magic(self, *args, **kwargs) :
            print("start magic")
            foo(self, *args, **kwargs)
            print("end magic")
        return magic
    @Decorators.decorator
    def bar( self ) :
        print("normal call")
test = Test()
test.bar()结果:
>>> test = Test()
>>> test.bar()
start magic
normal call
end magic
>>> 
