Domanda

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

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 assume that C._x is a list. In init it is simply set to []. So if I do the following:

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

c.x will be set to [1,2,3]. What I want to be able to do now is

#...
c.x += 4

So that c.x is now [1,2,3,4]. The example is trivial, but obviously, I'd want the setx and getx methods to include some sort of processing and checks. Otherwise, using this approach would be silly.

Edit: It might be good enough to just use the __add__ method on C to enforce the behaviour, but I wondered if it was possibly to put the behaviour on the property instead of the whole class

È stato utile?

Soluzione

You can't overload operator for a specific attribute, because :

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

So in fact you are calling the __iadd__ operator of list. If you want to be able to do that, you have to create a new class, extending list, and overload operator __iadd__ or __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])

Altri suggerimenti

No, that won't work.

Basically, here's what happens:

c.x += 4

This code is equivalent to this:

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

However, temp here will be the list of 3 values, and this code doesn't work:

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

You get:

TypeError: 'int' object is not iterable

So this has nothing to do with the property, and everything to do with the fact that the code needs to look like this:

temp += [4]

So this works:

c.x += [4]

This cannot:

c.x += 4

This is one possible solution. You might readjust the behaviour of the __iadd__-method.

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 following:

>>> 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 sum it up: You can't overload the operator inside C's setitem-method, because incrementing is not an operation on the attribute, but the underlying list (as your attribute is just a variable pointing to that list-object). See my comment and the other answers, as well.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top