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, поэтому будьте осторожны)

2 ответов


если нет определенной причины использовать класс в качестве декоратора, я думаю, что обычно проще использовать функции для определения декораторов.

вот один из способов создать декоратор класса 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]

вот версия 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()