装饰所有类方法,而不是每次都重新装饰

时间:2015-11-02 14:56:08

标签: python

我有一个实例化一堆类的类。我不希望这些类中的每一个都被装饰(出于测试目的),所以我用包装器将它们包装在主类中,而包装器又包装了所有方法。当我创建该类的多个实例时,它的函数已经被包装,因为我使用未实例化的对象来准备它。有没有一种好方法可以避免每次都重新包装它们?

简化示例:

UserResource.py:

class UserResource(object):
    def test(self):
        pass

resource.py:

def resource_wrapper(resource_class):
    def decorate(cls):
        for attr in cls.__dict__:
            if callable(getattr(cls, attr)) and not attr.startswith('_'):
                setattr(cls, attr, _function_wrapper(getattr(cls, attr)))
        return cls
    return decorate(resource_class)


def _function_wrapper(fn):
    from functools import wraps

    @wraps(fn)
    def wrapper(*args, **kwargs):
        self = args[0]
        arg = kwargs.pop('test', False)

        print arg  # See output further down

        return fn(*args, **kwargs)

    return wrapper

tl; dr 一堆未实例化的类,用包装所有函数的包装器包装。函数每次运行时都会被包装。

当我运行时,我看到以下行为:

r1 = resource_wrapper(UserResource)()
r1.test(test=True)
# True

r2 = resource_wrapper(UserResource)()
r2.test(test=True)
# True
# False

r3 = resource_wrapper(UserResource)()
r3.test(test=True)
# True
# False
# False

有没有办法只包装一次而不是每次?

2 个答案:

答案 0 :(得分:0)

您应该看一下实现模板模式。这将为您提供标题中的共性,以及您可以仅在派生中实现的变体。

我无法从您的问题中提取更多信息,但也许策略模式可以提供解决方案。

/**
 * An abstract class that is common to several games in
 * which players play against the others, but only one is
 * playing at a given time.
 */

abstract class Game {
 /* Hook methods. Concrete implementation may differ in each subclass*/
    protected int playersCount;
    abstract void initializeGame();
    abstract void makePlay(int player);
    abstract boolean endOfGame();
    abstract void printWinner();

    /* A template method : */
    public final void playOneGame(int playersCount) {
        this.playersCount = playersCount;
        initializeGame();
        int j = 0;
        while (!endOfGame()) {
            makePlay(j);
            j = (j + 1) % playersCount;
        }
        printWinner();
    }
}

//Now we can extend this class in order 
//to implement actual games:

class Monopoly extends Game {

    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        // Initialize money
    }
    void makePlay(int player) {
        // Process one turn of player
    }
    boolean endOfGame() {
        // Return true if game is over 
        // according to Monopoly rules
    }
    void printWinner() {
        // Display who won
    }
    /* Specific declarations for the Monopoly game. */

    // ...
}

class Chess extends Game {

    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        // Put the pieces on the board
    }
    void makePlay(int player) {
        // Process a turn for the player
    }
    boolean endOfGame() {
        // Return true if in Checkmate or 
        // Stalemate has been reached
    }
    void printWinner() {
        // Display the winning player
    }
    /* Specific declarations for the chess game. */

    // ...
}

答案 1 :(得分:0)

我通过改变操作实例化对象而不是类本身来修复它。

我的resource_wrappers如果更改为for attr in dir(cls):,我将cls传递给_function_wrapper,并将其作为self使用。

为清楚起见,这是示例代码的最终结果:

<强> UserResource.py:

class UserResource(object):
    def test(self):
        pass

<强> resource.py:

def resource_wrapper(resource_class):
    def decorate(cls):
        for attr in dir(cls):
            if callable(getattr(cls, attr)) and not attr.startswith('_'):
                setattr(cls, attr, _function_wrapper(cls, getattr(cls, attr)))
        return cls
    return decorate(resource_class)


def _function_wrapper(cls, fn):
    from functools import wraps

    @wraps(fn)
    def wrapper(*args, **kwargs):
        self = cls
        arg = kwargs.pop('test', False)

        print arg  # See output further down

        return fn(*args, **kwargs)

    return wrapper

<强>用法:

r1 = resource_wrapper(UserResource())
r1.test(test=True)
# True