装饰所有类方法而不重新装饰每个类

2024-03-28 10:31:22 发布

您现在位置:Python中文网/ 问答频道 /正文

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

简化示例:

用户资源.py:

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

资源.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
太长了,读不下去了,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

有没有办法只包装一次函数而不是每次包装一次?你知道吗


Tags: 实例函数testfalsetruereturndefargs
2条回答

您应该看看如何实现模板模式。这将为您提供标头中的通用性,以及仅在派生中实现的变体。你知道吗

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

/**
 * 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. */

    // ...
}

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

如果将我的资源包装器更改为for attr in dir(cls):,我将cls传递给self函数包装器。你知道吗

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

用户资源.py:

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

资源.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

相关问题 更多 >