简体   繁体   English

Python通过装饰类动态地将装饰器添加到类的方法中

[英]Python dynamically add decorator to class' methods by decorating class

say I have a class: 说我上课了:

class x:

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

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

and this decorator 和这个装饰

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

how would I write another decorator otherdecorator so that: 我将如何编写另一个装饰器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...'

the same as 同样的

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...'

or in fact replace 或实际上取代

@otherdecorator(logger.log)
class x:

with

@otherdecorator 
class x:

where otherdecorator contains all the functionality (I'm not a python person so be gentle) 其他装饰者包含所有功能(我不是蟒蛇人,所以要温柔)

Unless there is a definite reason to use a class as a decorator, I think it is usually easier to use functions to define decorators. 除非有明确的理由将类用作装饰器,否则我认为使用函数定义装饰器通常更容易。

Here is one way to create a class decorator trace , which decorates all methods of a class with the log decorator: 这是创建类装饰器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 as e:
                print('Exception in %s : %s' % (func.__name__, e))
        finally:
            print("Exiting: [%s]" % func.__name__)
    return wrapped


def trace(cls):
    # https://stackoverflow.com/a/17019983/190597 (jamylak)
    for name, m in inspect.getmembers(cls, lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
        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()

yields: 收益率:

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

Here's a version of the trace decorator implemented as a class which allows for the other use case asked for: passing in the function to decorate all member functions of the decorated class with. 这是一个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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM