2009-04-15 107 views
4

我正在为必须检查父方法(在装饰类的父类中同名的方法)编写方法的装饰器。从装饰器访问拥有装饰方法的类

例(从PEP 318第四例):

def returns(rtype): 
    def check_returns(f): 
     def new_f(*args, **kwds): 
      result = f(*args, **kwds) 
      assert isinstance(result, rtype), \ 
        "return value %r does not match %s" % (result,rtype) 
      return result 
     new_f.func_name = f.func_name 
     # here I want to reach the class owning the decorated method f, 
     # it should give me the class A 
     return new_f 
    return check_returns 

class A(object): 
    @returns(int) 
    def compute(self, value): 
     return value * 3 

所以我在寻找的代码代替#我在这里要输入...

感谢。

回答

6

由于bobince said it,你不能访问周围的类,因为在调用装饰器时,该类还不存在。如果您需要访问类和基地的全部字典,你应该考虑metaclass

__metaclass__

这个变量可以是名,碱和字典的任何调用接受参数。在创建类时,将使用可调用对象而不是内置类型()。

基本上,我们转换returns装饰到的东西,只是告诉元类上做一流的施工某种魔力:

class CheckedReturnType(object): 
    def __init__(self, meth, rtype): 
     self.meth = meth 
     self.rtype = rtype 

def returns(rtype): 
    def _inner(f): 
     return CheckedReturnType(f, rtype) 
    return _inner 

class BaseInspector(type): 
    def __new__(mcs, name, bases, dct): 
     for obj_name, obj in dct.iteritems(): 
      if isinstance(obj, CheckedReturnType): 
       # do your wrapping & checking here, base classes are in bases 
       # reassign to dct 
     return type.__new__(mcs, name, bases, dct) 

class A(object): 
    __metaclass__ = BaseInspector 
    @returns(int) 
    def compute(self, value): 
     return value * 3 

记住,我没有测试此代码,请我是否应该发表评论更新这个。

有一些articles on metaclasses由强烈推荐的大卫Mertz,你可能会发现在这方面的有趣。

+0

我没有直接使用你的代码,因为我的问题比我告诉你的更具体。但是,在遍历* dct *时使用* name *有点奇怪,因为* name *通常用于* type *构造。谢谢,我认为无论如何接受你的答案都可以,因为它对我有很大的帮助。 – Gra 2009-04-16 13:08:27

6

这里我想达到的类拥有装饰方法F

你不能因为在装修的点,没有类拥有的方法F.

class A(object): 
    @returns(int) 
    def compute(self, value): 
     return value * 3 

是一样的话说:

class A(object): 
    pass 

@returns(int) 
def compute(self, value): 
    return value*3 

A.compute= compute 

显然,之前的功能被分配给所有者类returns()装饰建成。

现在,当你为一个类写入一个函数(内联或者像这样显式)时,它就成为一个未绑定的方法对象。 现在它有它的主人类,你可以这样得到一个参考:

>>> A.compute.im_class 
<class '__main__.A'> 

所以,你可以阅读f.im_class内“new_f”,这是在转让之后执行的,而不是在装饰本身。如果你不需要依靠CPython的实现细节,那么它有点难看,我不太清楚你想做什么,但涉及“获得所有者类”的东西是通常可以使用元类来实现。)