从装饰器中访问拥有装饰方法的类
我正在为一些方法写一个装饰器,这些方法需要检查它们的父类方法(也就是在我装饰的类的父类中同名的方法)。
举个例子(来自于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
所以我在寻找可以替代# 这里我想要...的代码。
谢谢。
2 个回答
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'>
所以你可以在‘new_f’里面读取 f.im_class,这个是在赋值之后执行的,但在装饰器本身里是做不到的。
(即使这样,如果你不需要的话,依赖 CPython 的实现细节也有点不太好。我不太确定你想要做什么,但涉及“获取拥有类”的事情,通常可以通过元类来实现。)
6
正如bobince所说,你无法访问周围的类,因为在装饰器被调用时,类还不存在。如果你需要访问类的完整字典和基类,你可以考虑使用 metaclass(元类):
__metaclass__
这个变量可以是任何一个可以接受名称、基类和字典作为参数的可调用对象。在创建类的时候,这个可调用对象会替代内置的type()。
基本上,我们把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
请注意,我没有测试这段代码,如果需要更新,请留言告诉我。
还有一些关于元类的文章,作者是非常推荐的David Mertz,你可能会觉得这些内容在这个上下文中很有趣。