【问题标题】:Accessing the class that owns a decorated method from the decorator从装饰器访问拥有装饰方法的类
【发布时间】:2009-04-15 20:23:35
【问题描述】:

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

示例(来自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 I want...

谢谢。

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    作为bobince said it,你无法访问周围的类,因为在调用装饰器时,该类还不存在。如果您需要访问类和基础的完整字典,您应该考虑使用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
    

    请注意,我尚未测试此代码,如果我要更新此代码,请离开 cmets。

    有一些 articles on metaclasses 由极力推荐的 David Mertz 撰写,在这种情况下您可能会觉得有趣。

    【讨论】:

    • 我没有直接使用你的代码,因为我的问题比我告诉你的要具体得多。但是在遍历 dct 时使用 name 有点奇怪,因为 name 通常用于 type 构造中。谢谢,我认为无论如何都可以接受您的回答,因为它对我帮助很大。
    【解决方案2】:

    这里我想访问拥有装饰方法 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 实现细节也有点难看。我不太确定您要做什么,但是涉及“获取所有者类”的事情通常是可以使用元类。)

    【讨论】:

      猜你喜欢
      • 2020-01-11
      • 2014-01-14
      • 1970-01-01
      • 2011-06-26
      • 1970-01-01
      • 2020-01-02
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多