Make python @property handle + =, - = etc

from the Python documentation , I see that you can configure methods for transparently handling properties:

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.")

Now suppose that C._xis a list. In init, it just installs on []. Therefore, if I do the following:

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

c.xvalue will be set [1,2,3]. Now I want to be able

#...
c.x += 4

So c.xnow [1,2,3,4]. An example is trivial, but, obviously, I would like to methods setxand getxinclude some processing and verification. Otherwise, using this approach would be foolish.

: , __add__ C, , ,

+4
3

, :

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])
+4

, .

, :

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
+2

This is one of the possible solutions. You can change the behavior of the method __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])

Usage is as follows:

>>> 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]

To summarize: you cannot overload an operator inside Csetitem-method, because incrementing is not an operation for an attribute, but a basic list (since your attribute is just a variable pointing to that list, an object). See my comment and other answers.

0
source

Source: https://habr.com/ru/post/1538033/


All Articles