Is there a way in python to increment int object in place, int doesn’t seem to implement __iadd__ so += 1 actually returns a new object
>>> n=1 >>> id(n) 9788024 >>> n+=1 >>> id(n) 9788012
What I want is n to remain pointing to same object.
Purpose: I have class derived from int and I want to implement C type ‘++n’ operator for that class
Conclusion: ok as int is immutable there is no way, looks like i will have to write my own class something like this
class Int(object):
def __init__(self, value):
self._decr = False
self.value = value
def __neg__(self):
if self._decr:
self.value -= 1
self._decr = not self._decr
return self
def __str__(self):
return str(self.value)
def __cmp__(self, n):
return cmp(self.value, n)
def __nonzero__(self):
return self.value
n = Int(10)
while --n:
print n
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
ints are immutable, so you’ll have to build your own class with all the int’s methods if you want a “mutable int”
Method 2
You can use ctypes as mutable integers. Choosing the right ctype will be important though, as they limit the size of integer they can carry.
>>> from ctypes import c_int64 >>> num = c_int64(0) >>> id(num) 4447709232 >>> def increment(number): ... number.value += 1 ... >>> increment(num) >>> increment(num) >>> increment(num) >>> num.value 3 >>> id(num) 4447709232 >>>
More info: https://docs.python.org/2/library/ctypes.html#fundamental-data-types
Method 3
If you absolutely have to get that code to work, here’s a dirty method, where an instance method moves up a frame and overwrites its own locals entry. Wouldn’t recommend. (like, really not. I’m not even sure what that does. What happens to the old instance? I don’t know enough about frames…). Really, I’m only posting this because everyone said it’s impossible, when in reality it’s just ridiculously bad form. 😉
import sys
class FakeInt(int):
def __init__(self, *arg, **kwarg):
self._decr = False
int.__init__(self, *arg, **kwarg)
def __neg__(self):
if self._decr:
upLocals = sys._getframe(1).f_locals
keys, values = zip(*upLocals.items())
i = list(values).index(self)
result = FakeInt(self-1)
upLocals[keys[i]]=result
return result
self._decr = not self._decr
return self
A = FakeInt(10)
while --A:
print A,
outputs:
9 8 7 6 5 4 3 2 1
Method 4
You can put an immutable object inside a mutable container; lists are easiest.
This code prints 0, demonstrating the problem:
a = 0 # `a` points to a new int (a `0`) b = a # `b` points to the same thing as `a` (the `0`) b = 1 # `b` points to a new int (a `1`) print(a) # `a` still points to the same thing (the `0`)
If you put the int in a list, but otherwise use the same code as before, you can get the effect of having a mutable int (though it’s the list that is being mutated really):
a = [0] # `a` points to a new `0` inside a new list b = a # `b` points to the same thing as `a` (the list) b[0] = 1 # the list that `a` and `b` point to is mutated print(a[0]) # `a[0]` points to the same object as `b[0]` (the `1`)
In practice, you should structure your data so that the above ‘trick’ is redundant. The examples should not be used directly, but should help you figure out what to do.
Method 5
It would probably be easier to create a class that implements the int methods and wraps an internal integer.
Method 6
Yes, the short answer is that, ints are immutable.
Method 7
I had a similar issue today and came up with a class called IterInt that lets you increment or decrement in place using “+” and “-” decorators.
Usage:
x = IterInt() print x # result: 0 print +x # result: 1 print +x # result: 2 print +x # result: 3 print -x # result: 2 print -x # result: 1 print -x # result: 0
In my case I had a situation where I wanted to modify an application’s existing menu by inserting several command items after a specific index. The provided API I’m using has an “addCommand” function that can take an index at which to insert.
Consider this pseudo code where menu has commands a through g, something like menu = [a, f, g], and I want to insert b-e at index 1-4
idx = 1 menu.addCommand(b, index=idx) idx += 1 menu.addCommand(c, index=idx) idx += 1 menu.addCommand(d, index=idx) idx += 1 menu.addCommand(e, index=idx) idx += 1 # result: menu = [a, b, c, d, e, f]
It would be nice if I could write it so idx increments in place like c where I could do idx++, but functions do not allow python’s idx+=1 methodology in arguments.
Solution:
class IterInt(int):
"""
This function will return the next integer from the init_value starting point or 0 if None.
Each subsequent call to increment returns the next value
:param init_value:
:return:
"""
def __init__(self, init_value=None):
if init_value is None:
init_value = 0
if init_value is not None:
self.increment_value = init_value
self.increment_value = init_value
def __pos__(self):
self.increment_value += 1
return self.increment_value
def __neg__(self):
self.increment_value -= 1
return self.increment_value
idx = IterInt(1)
menu.addCommand(b, index=+idx)
menu.addCommand(c, index=+idx)
menu.addCommand(d, index=+idx)
menu.addCommand(e, index=+idx)
# result: menu = [a, b, c, d, e, f]
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0