2012-07-03 50 views
2

我正在尝试编写修改其类的状态的类方法装饰器。目前我遇到了麻烦。修改绑定方法及其类的Python装饰器状态

侧面问题:什么时候装饰器被调用?它是在类被实例化的时候加载的,还是在类读取的读取期间加载的?

我想要做的是这样的:

class ObjMeta(object): 
    methods = [] 

    # This should be a decorator that magically updates the 'methods' 
    # attribute (or list) of this class that's being read by the proxying 
    # class below. 
    def method_wrapper(method): 
     @functools.wraps(method) 
     def wrapper(*args, **kwargs): 
      ObjMeta.methods.append(method.__name__) 
      return method(*args, **kwargs) 
     return wrapper 

    # Our methods 
    @method_wrapper 
    def method1(self, *args): 
     return args 

    @method_wrapper 
    def method2(self, *args): 
     return args 


class Obj(object): 

    klass = None 

    def __init__(self, object_class=ObjMeta): 
     self.klass = object_class 
     self._set_methods(object_class) 

    # We dynamically load the method proxies that calls to our meta class 
    # that actually contains the methods. It's actually dependent to the 
    # meta class' methods attribute that contains a list of names of its 
    # existing methods. This is where I wanted it to be done automagically with 
    # the help of decorators 
    def _set_methods(self, object_class): 
     for method_name in object_class: 
      setattr(self, method_name, self._proxy_method(method_name)) 

    # Proxies the method that's being called to our meta class 
    def _proxy_method(self, method_name): 
     def wrapper(*fargs, **fkwargs): 
      return getattr(self.klass(*fargs, **fkwargs), method_name) 
     return wrapper() 

我认为这是丑陋的类手工编写的方法列表,这样也许会装饰解决这个问题。

这是一个开源项目,我正在将端口underscore.js工作到python。我明白,它说我应该只使用itertools什么的。我只是为了爱编程和学习而做这个。顺便说一句,项目托管here

谢谢!

+0

装饰者应该在创建类对象时运行。 (*不是*当这个类的实例正在创建时。)这通常发生在第一次导入模块时。 – millimoose

+0

谢谢!这回答了我的另一个问题。帮助很多。 – jpanganiban

+1

这与函数式编程有什么关系? – Ben

回答

1

这里有一些错误。

当调用方法本身时,内部包装中的任何内容都会被调用。基本上,你用这个函数替换原来的方法。所以,你的代码在它每次调用时会将方法名称添加到列表中,这可能不是你想要的。相反,该附加应该在method_wrapper级别,即内部包装之外。这是在定义方法时调用的,这是在第一次导入包含该类的模块时发生的。

错误的第二件事是,你从来没有实际调用该方法 - 你只需返回它。而不是return method您应该返回使用提供的参数调用方法的值 - return method(*args, **kwargs)

+0

哎呀。你是对的。我应该返回传入的方法和* args和** kwargs。我将编辑上面的代码。至于你的回答,你也可能就在那里。我会放弃并回传。谢谢。 – jpanganiban

+0

太棒了!得到它的工作。我创建了另一个由ObjMeta继承的类,它包含'methods'属性,这就是我在method_wrapper中修改的内容:ObjMetaMeta.methods.append(method .__ name__) – jpanganiban