Property setters for compound assignment? - python

Consider the following simple example class, which has a property that exposes a modified version of some internal data when called:
class Foo(object):
def __init__(self, value, offset=0):
self._value = value
self.offset = offset
#property
def value(self):
return self._value + self.offset
#value.setter
def value(self, value):
self._value = value
The value.setter works fine for regular assignment, but of course breaks down for compound assignment:
>>> x = Foo(3, 2)
>>> x.value
5
>>> x.value = 2
>>> x.value
4
>>> x.value += 5
>>> x.value
11
The desired behavior is that x.value += 5 should be equivalent to x.value = x._value + 5, as opposed to x.value = x.value + 5. Is there any way to achieve this (with the property interface) purely within the Foo class?

#ezod, there is no direct way to do what you're asking for, even with the descriptors protocol.
That kind behaviour of value property totally breaks the semantics of += operator.

Override the __iadd__ magic method.
You need to do that because += means "take the value and add five, then set that as the result". If you want it to know that the value isn't really the value, you need to change the semantics of the += operator.

I was confronted with the same problem and solved it with the following method:
class Foo(object):
def __init__(self):
self._y = 0
#property
def y(self):
return self._y + 5
#y.setter
def y(self, value):
value -= 5
self._y = value
>>> f = Foo()
>>> f.y
5
>>> f.y += 1
>>> f._y
1
>>> f.y
6
Could this be a solution? Have I overlooked something?

The desired behavior is that x.value += 5 should be equivalent to
x.value = x._value + 5
Why should Python know how you property is implemented (i.e. that setter assigns its value exactly to _x)?
Protocol of property gives you a possibility assign different actions (get, set, delete) to one name. And this protocol doesn't care about a way of implementation of these actions.
So it would be quite confusable if Python make some assumptions about your code and try to modify strait forward code logic.

Related

How to make default (resettable) int in python

I'd like to have an ability to reset an integer/float to the predefined default value without overriding all arithmetic operations. Something like
class DefaultInt(int):
def __init__(self, value):
super(DefaultInt, self).__init__(value)
self.default_value = value
def reset(self):
self.value = self.default_value
my_int = DefaultInt(19)
my_int += 1
my_int.reset()
But there are two problems:
I cannot access the hidden value itself by subclassing int class.
After my_int += 1 the my_int becomes, obviously, a simple int.
Your immediate problems:
in-place addition needs you to redefine __iadd__ (in-place addition) to return a DefaultInt object (better save the default value, else it becomes the new value)
The reset thing looks not possible as you've written, just because integers are immutable. But you could assign back the result of reset to the same name. That would work.
class DefaultInt(int):
def __init__(self,value=0):
super(DefaultInt, self).__init__()
self.default_value = value
def __iadd__(self,value):
old_default = self.default_value
r = DefaultInt(value + self)
r.default_value = old_default
return r
def reset(self):
return DefaultInt(self.default_value)
my_int = DefaultInt(19)
my_int += 1
print(my_int)
my_int = my_int.reset()
print(my_int)
output:
20
19
Your long-term problems:
But that's a first step. If you try my_int + 12 you'll see that it returns an int as well: you'll have to define __add__. Same goes for __sub__... and there's the "hidden" value problem, and the immutable problem which prevents you to perform an in-place reset.
Conclusion:
I think the best approach would be not to inherit int and create your own, mutable, class with all the special methods crafted for your needs (plus the reset method that would work now). You won't have the constraints you're having when overriding int, and your code will be clearer, even if method-exhaustive (at least if a method is missing, you'll notice it, instead of calling a method that doesn't fit).
I think that, if you only need a reset function, you can simply use:
default_value = 5
my_int = int.__new__(int, default_value)
my_int += 1
print my_int # prints 6
my_int = int.__new__(int, default_value)
print my_int # prints 5

When to store things as part of an instance vs returning them?

I was just wondering when to store things as part of a class instance versus when to use a method to return things. For example, which of the following would be better:
class MClass():
def __init__(self):
self.x = self.get_x()
self.get_y()
self.z = None
self.get_z()
def get_x(self):
return 2
def get_y(self):
self.y = 5 * self.x
def get_z(self):
return self.get_x() * self.x
What are the conventions regarding this sort of thing and when should I assign things to self and when should I return values? Is this essentially a public/private sort of distinction?
You shouldn't return anything from __init__.
Python is not Java. You don't need to include get for everything.
If x is always 2 and y is always 10 and z is always 12, that is a lot of code.
Making some assumptions, I would write that class:
class MClass(object):
def __init__(self, x):
self.x = x
def y(self):
return self.x * 5
def z(self):
return self.x + self.y()
>>> c = MClass(2)
>>> c.x
2
>>> c.y() # note parentheses
10
>>> c.z()
12
This allows x to change later (e.g. c.x = 4) and still give the correct values for y and z.
You can use the #property decorator:
class MClass():
def __init__(self):
self.x = 2
#property
def y(self):
return 5 * self.x
#here a plus method for the setter
#y.setter
def y(self,value):
self.x = y/5
#property
def z(self):
return self.x * self.x
It's a good way of organizing yours acessors
There's no "conventions" regarding this, AFAIK, although there're common practices, different from one language to the next.
In python, the general belief is that "everything is public", and there's no reason at all to have a getter method just to return the value of a instance variable. You may, however, need such a method if you need to perform operations on the instance when such variable is accessed.
Your get_y method, for example, only makes sense if you need to recalculate the expression (5 * self.x) every time you access the value. Otherwise, you should simply define the y variable in the instance in __init__ - it's faster (because you don't recalculate the value every time) and it makes your intentions clear (because anyone looking at your code will immediately know that the value does not change)
Finally, some people prefer using properties instead of writing bare get/set methods. There's more info in this question
I read your question as a general Object Oriented development question, rather than a python specific one. As such, the general rule of member data would be to save the data as a member of the class only if it's relevant as part of a particular instance.
As an example, if you have a Screen object which has two dimensions, height and width. Those two should be stored as members. The area associated with a particular instance would return the value associated with a particular instance's height and width.
If there are certain things that seem like they should be calculated on the fly, but might be called over and over again, you can cache them as members as well, but that's really something you should do after you determine that it is a valid trade off (extra member in exchange for faster run time).
get should always do what it says. get_y() and get_z() don't do that.
Better do:
class MClass(object):
def __init__(self):
self.x = 2
#property
def y(self):
return 5 * self.x
#property
def z(self):
return self.x * self.x
This makes y and z always depend on the value of x.
You can do
c = MClass()
print c.y, c.z # 10, 4
c.x = 20
print c.y, c.z # 100, 400

Avoiding unncessary use of lambda for calls to object methods

Consider the following code, which simply calls a method on each member of a list:
class Demo:
def make_change(self):
pass
foo = [Demo(), Demo(), Demo()]
map(lambda x: x.make_change(), foo)
Is there a way to accomplish this without the long-winded lambda syntax? For example, in Scala, something similar to map(_.make_change(), foo) works. Does Python have an equivalent?
It's not very pythonic to use map just for side-effects
so why not
for item in foo:
item.make_change()
This will run faster than using map
you can put it on one line if you insist, but I wouldn't
for item in foo:item.make_change()
operator.methodcaller('make_change')
I'm with gnibbler on the pythonicity. Apart from that, this is also possible:
map(Demo.make_change, foo)
It has problems, though:
class Demo(object):
def __init__(self):
self.x = 1
self.y = 2
def make_change(self):
self.x = 5
class SubDemo(Demo):
def make_change(self):
self.y = 7
d = Demo()
s = SubDemo()
map(Demo.make_change, [d, s])
assert d.x == 5 and s.y == 7 # oops!

Overriding "+=" in Python? (__iadd__() method)

Is it possible to override += in Python?
Yes, override the __iadd__ method. Example:
def __iadd__(self, other):
self.number += other.number
return self
In addition to what's correctly given in answers above, it is worth explicitly clarifying that when __iadd__ is overriden, the x += y operation does NOT end with the end of __iadd__ method.
Instead, it ends with x = x.__iadd__(y). In other words, Python assigns the return value of your __iadd__ implementation to the object you're "adding to", AFTER the implementation completes.
This means it is possible to mutate the left side of the x += y operation so that the final implicit step fails. Consider what can happen when you are adding to something that's within a list:
>>> x[1] += y # x has two items
Now, if your __iadd__ implementation (a method of an object at x[1]) erroneously or on purpose removes the first item (x[0]) from the beginning of the list, Python will then run your __iadd__ method) & try to assign its return value to x[1]. Which will no longer exist (it will be at x[0]), resulting in an ÌndexError.
Or, if your __iadd__ inserts something to beginning of x of the above example, your object will be at x[2], not x[1], and whatever was earlier at x[0] will now be at x[1]and be assigned the return value of the __iadd__ invocation.
Unless one understands what's happening, resulting bugs can be a nightmare to fix.
In addition to overloading __iadd__ (remember to return self!), you can also fallback on __add__, as x += y will work like x = x + y. (This is one of the pitfalls of the += operator.)
>>> class A(object):
... def __init__(self, x):
... self.x = x
... def __add__(self, other):
... return A(self.x + other.x)
>>> a = A(42)
>>> b = A(3)
>>> print a.x, b.x
42 3
>>> old_id = id(a)
>>> a += b
>>> print a.x
45
>>> print old_id == id(a)
False
It even trips up experts:
class Resource(object):
class_counter = 0
def __init__(self):
self.id = self.class_counter
self.class_counter += 1
x = Resource()
y = Resource()
What values do you expect x.id, y.id, and Resource.class_counter to have?
http://docs.python.org/reference/datamodel.html#emulating-numeric-types
For instance, to execute the statement
x += y, where x is an instance of a
class that has an __iadd__() method,
x.__iadd__(y) is called.

does python have conversion operators?

I don't think so, but I thought I'd ask just in case. For example, for use in a class that encapsulates an int:
i = IntContainer(3)
i + 5
And I'm not just interested in this int example, I was looking for something clean and general, not overriding every int and string method.
Thanks, sunqiang. That's just what I wanted. I didn't realize you could subclass these immutable types (coming from C++).
class IntContainer(int):
def __init__(self,i):
#do stuff here
self.f = 4
def MultiplyBy4(self):
#some member function
self *= self.f
return self
print 3+IntContainer(3).MultiplyBy4()
This should do what you need:
class IntContainer(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
# do some type checking on other
return self.x + other
def __radd__(self, other):
# do some type checking on other
return self.x + other
Output:
In [6]: IntContainer(3) + 6
Out[6]: 9
In [7]: 6 + IntContainer(3)
Out[7]: 9
For more information search for "radd" in the following docs:
http://docs.python.org/reference/datamodel.html#special-method-names
You'll find other such methods for "right addition", "right subtraction", etc.
Here's another link covering the same operators:
http://www.siafoo.net/article/57#reversed-binary-operations
By the way, Python does have casting operators:
http://www.siafoo.net/article/57#casts
But, they won't accomplish what you need in your example (basically because methods don't have any type annotation for parameters, so there's no good way to cast implicitly). So you can do this:
class IntContainer2(object):
def __init__(self, x):
self.x = x
def __int__(self):
return self.x
ic = IntContainer2(3)
print int(ic) + 6
print 6 + int(ic)
But this will fail:
print ic + 6 # error: no implicit coercion
You won't get conversion operators like in C++ because Python does not have this kind of strong static type system. The only automatic conversion operators are those which handle default numeric values (int/float); they are predefined in the language and cannot be changed.
Type "conversion" is usually done by constructors/factories. You can then overload standard methods like __add__ to make it work more like other classes.
sometimes maybe just subclass from int directly is enough. then __add__ and __radd__ need not costuming.
class IntContainer(int):
pass
i = IntContainer(3)
print i + 5 # 8
print 4 + i # 7
class StrContainer(str):
pass
s = StrContainer(3)
print s + '5' # 35
print '4' + s # 43
Is this what you need?
In [1]: class IntContainer(object):
...: def __init__(self, val):
...: self.val = val
...: def __add__(self, val):
...: return self.val + val
...: def __radd__(self, val):
...: return self.val + val
...:
...:
In [2]: i = IntContainer(3)
In [3]: i + 5
Out[3]: 8
In [4]:
Sorry for coming to the party 8.5 years late.
You can derive from an immutable (ie. int). You cannot define __init__ because the immutable is already created and can't be modified (by definition). This is where __new__ comes in handy.
class IntContainer(int):
def __new__ (cls, val):
ival = int.__new__(cls, val)
ival._rval = 'IntContainer(%d)' % ival
return ival
def __repr__ (self):
return self._rval
In [1]: i = IntContainer(3)
In [2]: i
Out[2]: IntContainer(3)
In [3]: repr(i)
Out[3]: 'IntContainer(3)'
In [4]: str(i)
Out[4]: '3'
In [5]: i + 5
Out[5]: 8
In [6]: 4 + i
Out[6]: 7
In [7]: int(i)
Out[7]: 3
In [8]: float(i)
Out[8]: 3.0
Now, to answer your question about conversion operators. You can also define __int__, __long__, __float__, and obviously, __str__. To convert or cast to an arbitrary object, you will most likely need to modify the other object to get what you want. You can use the __new__ method of that other object. Or if the other object is already created, try using __call__.

Categories