【问题标题】:Decorators that are properties of decorated objects?作为装饰对象属性的装饰器?
【发布时间】:2009-06-23 14:59:12
【问题描述】:

我想创建一个装饰器,它允许我引用被装饰的对象并从中获取另一个装饰器,就像在属性上使用 setter/deleter 一样:

@property
def x(self):
    return self._x

@x.setter
def x(self, y):
    self._x = y

具体来说,我希望它的行为与属性基本相同,但模拟一个序列而不是单个值。这是我的第一次尝试,但它似乎不起作用:

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)

我很确定c.__setitem__ = set 是错误的,但我不知道如何获得对实例的引用。想法?

Alex Martelli 的解决方案适用于 2.6,但它在 2.4 和 2.5 上失败了(我希望它也适用于这些旧版本,尽管这不是绝对必要的):

2.4:

>>> p = P()
>>> p.prop
>>> p.prop[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: unsubscriptable object

2.5:

>>> p = P()
>>> p.prop
>>> p.prop[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is unsubscriptable

2.6:

>>> p = P()
>>> p.prop
<__main__.c object at 0x017F5730>
>>> p.prop[0]
0

【问题讨论】:

  • 为什么不简单地将属性值设置为列表?
  • @S.Lott:因为我不需要列表,所以我需要一个看起来像列表的对象,但实际上通过使用列表索引作为附加参数从其他地方获取它的值.事实上,我需要其中的几个,它们都做非常相似但略有不同的事情。

标签: python decorator


【解决方案1】:

我修复了许多小细节,以下版本似乎可以按您的要求工作:

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.__setitem__ 不是问题——还有其他问题,例如 c 缺少 __get__(所以它不是描述符,请参阅 this guiide)和 setter 返回 None(所以p.prop 以 None 结束)。

【讨论】:

    猜你喜欢
    • 2014-10-02
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    • 2013-02-27
    • 2020-06-20
    • 2016-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多