我正在为必须检查父方法的方法编写装饰器(在我正在装饰的类的父级中使用相同名称的方法)。
示例(来自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
所以我正在寻找代码来代替#here here here
感谢。
答案 0 :(得分: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实现细节有点难看。我不太确定你要做什么,但涉及“获得所有者类”的事情往往是可以使用元类。)
答案 1 :(得分:6)
作为bobince said it,您无法访问周围的类,因为在调用装饰器时,该类尚不存在。如果您需要访问班级和基础的完整字典,您应该考虑metaclass:
__metaclass__
此变量可以是name,bases和dict的任何可调用接受参数。在创建类时,使用callable而不是内置类型()。
基本上,我们将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有一些articles on metaclasses,你可能会在这个背景下感兴趣。