【问题标题】:make python @property handle +=, -= etc使 python @property 处理 +=、-= 等
【发布时间】:2014-06-10 21:34:19
【问题描述】:

Python documentation,我看到你可以设置透明处理属性的方法:

class C(object):
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x

    x = property(getx, setx, delx, "I'm the 'x' property.")

现在假设C._x 是一个列表。在 init 中它被简单地设置为[]。因此,如果我执行以下操作:

c = C()
c.x = [1,2,3]

c.x 将设置为 [1,2,3]。我现在想做的是

#...
c.x += 4

所以c.x 现在是[1,2,3,4]。这个例子很简单,但很明显,我希望setxgetx 方法包括某种处理和检查。否则,使用这种方法将是愚蠢的。

编辑:C 上使用__add__ 方法来强制执行该行为可能就足够了,但我想知道是否可以将行为放在属性上而不是全班

【问题讨论】:

  • 你测试了吗?这对我来说似乎工作得很好。抱歉,我用[4] 进行了测试。发布了更多 cmets 和答案。
  • 不,不应该,如果c.x 是一个列表,因为[1, 2, 3] + 4 不合法,你需要将4 包装在一个列表中:[1, 2, 3] + [4]。含义:c.x += [4] 有效。
  • 不会的。我会得到 TypeError: int is not iterable,因为我不能将 4 添加到 [1,2,3]。我可以做 c.x += [4],但这不是我想要的
  • 该问题与物业无关。如果您可以诱使列表接受该语法,则该属性也将起作用。换句话说,将类和属性排除在等式之外,并使用x = [1, 2, 3]; x += 4 并使其正常工作。当你有这个工作时,该属性也会工作。
  • 你需要为这个重载 ````__iadd__``` 运算符(对于列表类型,因为没有 += 功能。因此,创建自己的列表类型并重载运算符。您无法在属性内实现此功能,请参阅stackoverflow.com/questions/19959359/…

标签: python class properties


【解决方案1】:

您不能为特定属性重载运算符,因为:

c.x += 4
# is equivalent to
c.x.__iadd__(4)

所以实际上你正在调用列表的__iadd__ 运算符。如果你想做到这一点,你必须创建一个新类、扩展列表和重载运算符__iadd____add__

class SuperList(list):
    def __iadd__(self, other):
        if type(other) == list or type(other) == SuperList:
            return super(SuperList, self).__iadd__(other)
        return super(SuperList, self).__iadd__([other])

【讨论】:

    【解决方案2】:

    不,这行不通。

    基本上,会发生以下情况:

    c.x += 4
    

    这段代码等价于:

    var temp = c.x
    temp += 4
    c.x = temp
    

    但是,temp 这里将是 3 个值的列表,并且此代码不起作用:

    temp = [1, 2, 3]
    temp += 4
    

    你得到:

    TypeError: 'int' 对象不可迭代

    所以这与属性无关,而与代码需要看起来像这样的事实有关:

    temp += [4]
    

    所以这行得通:

    c.x += [4]
    

    这不能:

    c.x += 4
    

    【讨论】:

    • 所以为了让它工作,我必须在 c._x 代表的类上创建一个__add__ 方法?这就是我想的......哦,好吧:P
    【解决方案3】:

    这是一种可能的解决方案。您可以重新调整__iadd__-方法的行为。

    class C(object):
        def __init__(self):
            # instanciate an empty list of your custom list-type
            self._x = MyList([])
    
        def getx(self):
            return self._x
    
        def setx(self, value):
            self._x = value
    
        def delx(self):
            del self._x
    
        x = property(getx, setx, delx, "I'm the 'x' property.")
    
    class MyList(list):
    
        def __iadd__(self,x):
            # if the item is an iterable, extend the list (standard __iadd__ behaviour)
            if hasattr(x,"__iter__"):
                return super(MyList,self).__iadd__(x)
            #if the item is not iterable, append it
            else:
                return super(MyList,self).__iadd__([x])
    

    用法如下:

    >>> c=C()
    >>> c.x+=1
    >>> c.x
        [1]
    >>> c.x+="test"
    >>> c.x
        [1,"test"]
    >>> c.x+=[3,4]
    >>> c.x
        [1,"test",3,4]
    

    总结一下:你不能在C的setitem-method中重载运算符,因为递增不是对属性的操作,而是底层列表(因为你的属性只是一个指向它的变量列表对象)。请参阅我的评论和其他答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-25
      • 2020-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多