Decorators that are properties of decorated objects?

22 阅读2分钟

我想创建一个修饰器,它允许我引用回被修饰的对象并从中获取另一个修饰器,就像你可以在属性上使用 setter/deleter 一样。我尝试了以下代码,但似乎不起作用:

def listprop(indices):
    def dec(func):
        class c(object):
            def __init__(self, l):
                self.l = l
            def __getitem__(self, i):
                if not i in self.l:
                    raise Exception("Invalid item: " + i)
                return func(i)
            @staticmethod
            def setter(func):
                def set(self, i, val):
                    if not i in self.l:
                        raise Exception("Invalid item: " + i)
                    func(i, val)
                c.__setitem__ = set
        return c(indices)
    return dec

# ...
class P:
    @listprop(range(3))
    def prop(self, i):
        return get_prop(i)

    @prop.setter
    def prop(self, i, val):
        set_prop(i, val)

Alex Martelli 的解决方案适用于 2.6,但它在 2.4 和 2.5 中会遇到问题,在 2.5 中,p.propNoneType,2.4 中,p.prop[0] 会抛出 TypeError: unsubscriptable object

2、解决方案:

以下是修改后的代码,它应该可以解决上述问题:

def listprop(indices):
    def dec(func):
        class c(object):
            def __init__(self, l, obj=None):
                self.l = l
                self.obj = obj
            def __get__(self, obj, cls=None):
                return c(self.l, obj)
            def __getitem__(self, i):
                if not i in self.l:
                    raise Exception("Invalid item: " + i)
                return func(self.obj, i)
            def setter(self, sfunc):
                def doset(self, i, val):
                    if not i in self.l:
                        raise Exception("Invalid item: " + i)
                    sfunc(self.obj, i, val)
                c.__setitem__ = doset
                return self
        result = c(indices)
        return result
    return dec

# ...
class P:
    @staticmethod
    def get_prop(i): return i*100

    @staticmethod
    def set_prop(i, val): print 'set %s to %s' % (i, val)

    @listprop(range(3))
    def prop(self, i):
        return self.get_prop(i)

    @prop.setter
    def prop(self, i, val):
        self.set_prop(i, val)

这段代码定义了一个类 c,它是修饰器的具体实现。c 类具有以下方法:

  • __init__: 构造函数,初始化 l 列表和 obj 对象。
  • __get__: 获取属性值的方法,返回一个新的 c 对象,该对象与 obj 对象相关联。
  • __getitem__: 获取列表项的方法,如果索引 il 列表中,则返回 func(obj, i) 的值。
  • setter: 设置属性值的方法,返回一个新的 c 对象,该对象具有一个新的 __setitem__ 方法,该方法用于设置列表项的值。
  • __setitem__: 设置列表项值的方法,如果索引 il 列表中,则调用 sfunc(obj, i, val) 来设置列表项的值。

修饰器 listpropc 类作为参数,并返回一个函数,该函数将 func 函数作为参数,并返回一个新的 c 对象,该对象与 func 函数相关联。

在类 P 中,prop 属性被修饰了,get_propset_prop 是静态方法,分别用于获取和设置属性值。

当调用 p.prop 时,它将返回一个 c 对象,该对象与 p 对象相关联。当调用 p.prop[i] 时,它将返回 func(p, i) 的值。当调用 p.prop.setter 时,它将返回一个新的 c 对象,该对象具有一个新的 __setitem__ 方法,该方法用于设置列表项的值。当调用 p.prop[i] = val 时,它将调用 __setitem__ 方法来设置列表项的值。