如何在python类中用方法替换decorator

如何在python类中用方法替换decorator,python,methods,decorator,Python,Methods,Decorator,假设我有下面的代码,其中我使用get_duration decorator打印出一个方法的持续时间 import datetime import time def get_duration(function): def wrapper(*args, **kwargs): start = datetime.datetime.now() print "starting process %s()" %function.__name__ function(*args, **

假设我有下面的代码,其中我使用get_duration decorator打印出一个方法的持续时间

import datetime
import time

def get_duration(function):
  def wrapper(*args, **kwargs):
    start = datetime.datetime.now()
    print "starting process %s()" %function.__name__
    function(*args, **kwargs)
    end = datetime.datetime.now()
    print "Process lasted: ", end - start
  return wrapper

class Operations(object):

  def __init__(self, a, b):
    self.a = a
    self.b = b

  @get_duration
  def add(self):
    time.sleep(1)
    print self.a + self.b

  @get_duration
  def sub(self):
    time.sleep(1)
    print self.a - self.b


my_class = Operations(2, 98)
my_class.add()
my_class.sub()
输出

>> starting process add()
>> 100
>> Process lasted:  0:00:01.000260
>> starting process sub()
>> -96
>> Process lasted:  0:00:01.001161
我可以用类方法或类似的东西来替换它(下面是伪代码):

您可以这样做:

def get_duration(function):
  def wrapper(*args, **kwargs):
    kwargs['self'].elapsed_time = timeit.timeit('function(*args, **kwargs)',
                                      "from __main__ import function, args, kwargs",
                                      number=1)
  return wrapper
然后,您可以读取经过的时间来获取时间。

您可以执行以下操作:

def get_duration(function):
  def wrapper(*args, **kwargs):
    kwargs['self'].elapsed_time = timeit.timeit('function(*args, **kwargs)',
                                      "from __main__ import function, args, kwargs",
                                      number=1)
  return wrapper

然后,您可以读取
appeated\u time
var来获取时间。

为了完全满足您的需要,您可以通过可调用类来修饰此方法

class TimeElapser  :
   def __init__(self, function_to_wrap) :
       self.__call__ = function_to_wrap
       self.get_duration = get_duration(function_to_wrap)
示例:

class Foo :

    @TimeElapser
    def do_something(self, ....) :
       ...

foo = Foo()
foo.do_something() #Does something
foo.do_something.get_duration() # Does something and print duration

为了完全满足您的需要,您可以通过callable类来修饰这个方法

class TimeElapser  :
   def __init__(self, function_to_wrap) :
       self.__call__ = function_to_wrap
       self.get_duration = get_duration(function_to_wrap)
示例:

class Foo :

    @TimeElapser
    def do_something(self, ....) :
       ...

foo = Foo()
foo.do_something() #Does something
foo.do_something.get_duration() # Does something and print duration
像这样的

def map_func(function):
    def wrapper(*args, **kwargs):
        start = datetime.datetime.now()
        print "starting process %s()" %function.__name__
        function(*args, **kwargs)
        end = datetime.datetime.now()
        print "Process lasted: ", end - start
    function.get_duration = wrapper
    return function
演示:

>>> c = Operations(100, 200)
>>> c.add()
c.300
>>> c.sub()
-100
>>> c.add.get_duration(c)
starting process add()
300
Process lasted:  0:00:01.001584
>>> c.sub.get_duration(c)
starting process sub()
-100
Process lasted:  0:00:01.003768
像这样的

def map_func(function):
    def wrapper(*args, **kwargs):
        start = datetime.datetime.now()
        print "starting process %s()" %function.__name__
        function(*args, **kwargs)
        end = datetime.datetime.now()
        print "Process lasted: ", end - start
    function.get_duration = wrapper
    return function
演示:

>>> c = Operations(100, 200)
>>> c.add()
c.300
>>> c.sub()
-100
>>> c.add.get_duration(c)
starting process add()
300
Process lasted:  0:00:01.001584
>>> c.sub.get_duration(c)
starting process sub()
-100
Process lasted:  0:00:01.003768

我认为这是元编程的一个很好的用例,比如:

import types

def my_dec(f):
    print "decorated"
    return f

class MyMetaprogrammingDecoratorClass(object):
    def __getattr__(self, attribute):
        try:
            ## we should honor inherited classes that may have defined __getattr__
            return super(MyMetaprogrammingDecoratorClass, self).__getattr__(attribute)
        except AttributeError:
            if attribute.endswith("_decorated"):
                output = object.__getattribute__(self, attribute.replace("_decorated",""))
                if isinstance(output, types.MethodType):
                    return my_dec(output)
                else:
                    raise AttributeError
            else:
                raise AttributeError

class MyCustomClass(MyMetaprogrammingDecoratorClass):
    def f(self):
        return 1

g = MyCustomClass()
print g.f()
>> 1
print g.f_decorated()
>> decorated
>> 1

因此,您可以用
\u decorded
对任何方法进行后缀,如果该方法存在,类将知道用
my\u dec
对该方法进行修饰。

我认为这是元编程的一个很好的使用案例:

import types

def my_dec(f):
    print "decorated"
    return f

class MyMetaprogrammingDecoratorClass(object):
    def __getattr__(self, attribute):
        try:
            ## we should honor inherited classes that may have defined __getattr__
            return super(MyMetaprogrammingDecoratorClass, self).__getattr__(attribute)
        except AttributeError:
            if attribute.endswith("_decorated"):
                output = object.__getattribute__(self, attribute.replace("_decorated",""))
                if isinstance(output, types.MethodType):
                    return my_dec(output)
                else:
                    raise AttributeError
            else:
                raise AttributeError

class MyCustomClass(MyMetaprogrammingDecoratorClass):
    def f(self):
        return 1

g = MyCustomClass()
print g.f()
>> 1
print g.f_decorated()
>> decorated
>> 1

因此,您可以用
\u decorded
对任何方法进行后缀,如果该方法存在,类将知道用
my\u dec
对该方法进行修饰。

您应该使用timeit模块来处理这类事情。谢谢,但这只是一个decorator示例。我对这个过程的计时不感兴趣。也许你可以直接使用装饰器,比如:get_duration(my_class.add)()?你应该使用timeit模块来处理这类事情。谢谢,但这只是装饰器的一个例子。我对这个过程的计时不感兴趣。可能你可以直接使用装饰器,比如:get_duration(my_class.add)()?不要每次都重新应用装饰器,你应该用
self.get_duration=get_duration(function)
在构造函数中分配它。否则,这是迄今为止发布的最干净的解决方案。我不确定我是否理解这是如何工作的。你能给出一个例子吗?这很有意义,但只有当dou something()的定义没有参数时,它才起作用……我如何将它调整为*args、**kwargs?所以,如果我做了'def dou something():打印“bar”'一切都很好,但是如果我做了'def dou something(参数)':打印“bar”+参数”,然后调用foo.dou something('my_argument')).get_duration()我将获得“AttributeError:'NoneType'对象没有属性'get_duration'”,您可以使用foo.do_something.get_duration('my_参数')。也许我误解了你的任务,就像@Ashwini Chaudhary一样。请将示例添加到您的问题中,因为现在公式不清楚。您不应该每次都重新应用装饰器,而应该使用
self.get\u duration=get\u duration(function)
在构造函数中分配它。否则,这是迄今为止发布的最干净的解决方案。我不确定我是否理解这是如何工作的。你能给出一个例子吗?这很有意义,但只有当dou something()的定义没有参数时,它才起作用……我如何将它调整为*args、**kwargs?所以,如果我做了'def dou something():打印“bar”'一切都很好,但是如果我做了'def dou something(参数)':打印“bar”+参数”,然后调用foo.dou something('my_argument')).get_duration()我将获得“AttributeError:'NoneType'对象没有属性'get_duration'”,您可以使用foo.do_something.get_duration('my_参数')。也许我误解了你的任务,就像@Ashwini Chaudhary一样。请在你们的问题中加上一个例子,因为现在公式还不清楚。