Вопрос по int, python – инкремент int объект
Есть ли способ в Python для увеличения объекта int на месте, int, кажется, не реализует__iadd__
так + = 1 на самом деле возвращает новый объект
>>> n=1
>>> id(n)
9788024
>>> n+=1
>>> id(n)
9788012
То, что я хочу, это чтобы n указывал на один и тот же объект.
Цель: у меня есть класс, производный от int, и я хочу реализовать тип C & amp; ++ n & apos; оператор для этого класса
Вывод: хорошо, так как int неизменяемый, нет пути, похоже, мне придется написать свой собственный класс примерно так
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
Интты являются неизменяемыми, поэтому вам нужно создать свой собственный класс со всеми методами int, если вы хотите & quot; изменяемый int & quot;
Вы можете использовать ctypes как изменяемые целые числа. Выбор правильного ctype будет важен, так как они ограничивают размер целого числа, которое они могут нести.
>>> 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
>>>
Больше информации:https://docs.python.org/2/library/ctypes.html#fundamental-data-types
У меня была похожая проблема сегодня, и я предложил класс IterInt, который позволяет вам увеличивать или уменьшать на месте, используя & quot; + & quot; и & quot; - & quot; декораторы.
Использование:
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
В моем случае у меня была ситуация, когда я хотел изменить существующее меню приложения, вставив несколько элементов команды после определенного индекса. Предоставленный API, который я использую, имеет & quot; addCommand & quot; функция, которая может взять индекс для вставки.
Рассмотрим этот псевдокод, в котором меню имеет команды от a до g, что-то вроде menu = [a, f, g], и я хочу вставить b-e с индексом 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]
Было бы хорошо, если бы я мог написать это так, чтобы idx увеличивался на месте, как c, где я мог бы делать idx ++, но функции не допускают методологию python 'idx + = 1 в аргументах.
Решение:
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]
x = IterInt(10)
, затем-x
равняется9
не-10
, Перегрузка операторов должна использоваться для того, чтобы операторы работали с экземплярами пользовательских классов так же, как они работают со встроенными типами. Вы можете создавать новые операторы для новых типов, но это следует оставить опытным разработчикам API. Это слишком легко упустить из виду.
Если вам абсолютно необходимо заставить этот код работать, то это грязный метод, где метод экземпляра перемещает кадр вверх и перезаписывает свою собственную запись локальных элементов. Не рекомендую. (например, на самом деле нет. Я даже не уверен, что это делает. Что происходит со старым экземпляром? Я недостаточно знаю о кадрах ...). Действительно, я публикую это только потому, что все говорят, что это невозможно, хотя на самом деле это просто смехотворно дурной тон. ;-)
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,
выходы:
9 8 7 6 5 4 3 2 1
Вы можете поместить неизменный объект в изменяемый контейнер; списки самые простые.
Этот код печатает0
, демонстрируя проблему:
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`)
Если вы помещаете int в список, но в остальном используете тот же код, что и раньше, вы можете получить эффект наличия изменяемого int (хотя это действительно изменяемый список):
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 # t,he list that `a` and `b` point to is mutated
print(a[0]) # `a[0]` points to the same object as `b[0]` (the `1`)
На практике вы должны структурировать свои данные так, чтобы вышеуказанный «трюк» избыточно Примеры не должны использоваться напрямую, но должны помочь вам понять, что делать.