2011-03-30 29 views
9
类添加装饰类方法

说,我有一个类:Python的动态通过装饰

class x: 

    def first_x_method(self): 
     print 'doing first_x_method stuff...' 

    def second_x_method(self): 
     print 'doing second_x_method stuff...' 

和这个装饰

class logger: 
    @staticmethod 
    def log(func): 
     def wrapped(*args, **kwargs): 
      try: 
       print "Entering: [%s] with parameters %s" % (func.__name__, args) 
       try: 
        return func(*args, **kwargs) 
       except Exception, e: 
        print 'Exception in %s : %s' % (func.__name__, e) 
      finally: 
       print "Exiting: [%s]" % func.__name__ 
     return wrapped 

如何将我写的另一个装饰otherdecorator使:

@otherdecorator(logger.log) 
class x: 

    def first_x_method(self): 
     print 'doing x_method stuff...' 

    def first_x_method(self): 
     print 'doing x_method stuff...' 

相同
class x: 
     @logger.log 
     def first_x_method(self): 
      print 'doing first_x_method stuff...' 

     @logger.log 
     def second_x_method(self): 
     print 'doing second_x_method stuff...' 

或事实上取代

@otherdecorator(logger.log) 
class x: 

@otherdecorator 
class x: 

其中otherdecorator包含了所有的功能 (我不是一个Python的人这么温柔)

+0

您使用的是什么版本的Python? – detly 2011-03-30 03:57:49

+0

2.6和铁蟒(clr 4.0/dlr) – 2011-03-30 08:35:53

回答

17

除非有一个使用类作为装饰器的明确理由,我认为使用函数来定义装饰器通常更容易。

下面是创建一个类装饰trace,其装饰与log装饰类的所有方法的一个方式:

import inspect 

def log(func): 
    def wrapped(*args, **kwargs): 
     try: 
      print "Entering: [%s] with parameters %s" % (func.__name__, args) 
      try: 
       return func(*args, **kwargs) 
      except Exception, e: 
       print 'Exception in %s : %s' % (func.__name__, e) 
     finally: 
      print "Exiting: [%s]" % func.__name__ 
    return wrapped 

def trace(cls): 
    for name, m in inspect.getmembers(cls, inspect.ismethod): 
     setattr(cls,name,log(m)) 
    return cls 

@trace 
class X(object): 
    def first_x_method(self): 
     print 'doing first_x_method stuff...' 
    def second_x_method(self): 
     print 'doing second_x_method stuff...' 

x=X() 
x.first_x_method() 
x.second_x_method() 

产量:

Entering: [first_x_method] with parameters (<__main__.X object at 0xb77c80ac>,) 
doing first_x_method stuff... 
Exiting: [first_x_method] 
Entering: [second_x_method] with parameters (<__main__.X object at 0xb77c80ac>,) 
doing second_x_method stuff... 
Exiting: [second_x_method] 
+0

真棒。非常感谢你。 – 2011-03-30 04:05:23

+0

所以大概我可以在运行时添加装饰器,并在类型上使用settattr来进行装配。 – 2011-03-30 09:00:24

+1

@Preet Sangha:是的,我不认为会有任何问题 - 除了在应用装饰器之前创建的类的实例不会被修改。 – unutbu 2011-03-30 12:32:09

2

这里的trace装饰的版本作为允许其他用例要求的类实现:传递函数来装饰装饰类的所有成员函数。

import inspect 


def log(func): 
    def wrapped(*args, **kwargs): 
     try: 
      print "Entering: [%s] with parameters %s" % (func.__name__, args) 
      try: 
       return func(*args, **kwargs) 
      except Exception, e: 
       print 'Exception in %s : %s' % (func.__name__, e) 
     finally: 
      print "Exiting: [%s]" % func.__name__ 
    return wrapped 


class trace(object): 

    def __init__(self, f): 
     self.f = f 

    def __call__(self, cls): 
     for name, m in inspect.getmembers(cls, inspect.ismethod): 
      setattr(cls, name, self.f(m)) 
     return cls 


@trace(log) 
class X(object): 

    def first_x_method(self): 
     print 'doing first_x_method stuff...' 

    def second_x_method(self): 
     print 'doing second_x_method stuff...' 

x = X() 
x.first_x_method() 
x.second_x_method() 
+0

不错的一个。谢谢。 – 2013-08-24 22:02:16