Что-то вроде этого сделало бы то, что вам нужно?
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
То, что вы хотите сделать, невозможно. Возьмем, к примеру, выглядит ли приведенный ниже код действительным:
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)
источник
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()
источник
@foo
, а не@foo()
wrapper
бытьself
?Я использую этот тип декоратора в некоторых ситуациях отладки, он позволяет переопределять свойства класса путем декорирования, без необходимости поиска вызывающей функции.
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 () со скобками для украшения функций, даже если вы не передаете никаких аргументов конструктору класса декоратора.
источник
Это один из способов доступа (и уже использованных)
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'
Приведенный выше пример глуп, но он работает.
источник
Я нашел этот вопрос, исследуя очень похожую проблему. Мое решение - разбить проблему на две части. Во-первых, вам нужно захватить данные, которые вы хотите связать с методами класса. В этом случае 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
источник
Вот расширение ответа Майкла Спира, чтобы сделать еще несколько шагов вперед:
Декоратор метода экземпляра, который принимает аргументы и действует с функцией с аргументами и возвращаемым значением.
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)
источник
Декораторы кажутся более подходящими для изменения функциональности всего объекта (включая функциональные объекты), чем функциональность метода объекта, который в целом будет зависеть от атрибутов экземпляра. Например:
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
источник
Украсить декоратор можно:
import decorator class Test(object): @decorator.decorator def _decorator(foo, self): foo(self) @_decorator def bar(self): pass
источник
У меня есть реализация декораторов, которые могут помочь
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)
источник
Объявить во внутреннем классе. Это решение довольно надежное и рекомендуется.
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 >>>
источник