2015-11-02 69 views
2

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

简化的例子:

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;博士一束非实例的类,包有一个包装所有功能的包装器。每次运行时都会封装函数。

当我运行此我看到以下行为:

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 

有没有办法只能换每次的功能,而不是一次的?

+1

听起来像你需要一个类工厂。不要在原地修改'UserResource',你应该编写一个返回包含包装方法的新类的函数。 –

+0

“为测试目的”是什么意思?我可能总是把它们包起来,并且把我的测试包装掉? –

+0

啊,是的,但不仅仅是为了测试的目的,我也希望这个类具有正常的行为,并且如果以这种特殊的方式使用了其他样板魔法的话。这很难解释,但请记住,上面的代码是一个非常简单的例子。 – olofom

回答

0

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

我resource_wrappers如果换成for attr in dir(cls):和我通过cls使用它作为self到_function_wrapper。

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

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

    // ... 
} 
+0

我并不完全确定你的模板模式的含义。你是指mixin? – olofom

+0

在这种设计模式的模板方法中,一个或多个算法步骤可以被子类覆盖以允许不同的行为,同时确保仍然遵循总体算法。 –

+0

啊,我明白你的意思了,我猜mixins会是这个特殊用例实现继承的最pythonesque方法。我想避免这种情况,并保留资源类(在我的示例中)UserResource完全清除更改,并让它们仅在特定用例中实例化时才被操作,因为我的图层在外部方法调用中添加了缓存等。 – olofom