инкремент int объект - PullRequest
14 голосов
/ 16 июля 2009

Есть ли в python способ увеличить объект int на месте, кажется, что int не реализует __iadd__, поэтому + = 1 фактически возвращает новый объект

>>> n=1
>>> id(n)
9788024
>>> n+=1
>>> id(n)
9788012

Мне нужно, чтобы n оставалось указывать на тот же объект.

Цель: у меня есть класс, унаследованный от int, и я хочу реализовать оператор типа C ++ n для этого класса

Вывод: хорошо, поскольку 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

Ответы [ 7 ]

12 голосов
/ 16 июля 2009

int являются неизменяемыми, поэтому вам нужно создать свой собственный класс со всеми методами int, если вы хотите "mutable int"

5 голосов
/ 27 февраля 2015

Вы можете использовать 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

5 голосов
/ 17 июля 2009

Если вам абсолютно необходимо заставить этот код работать, вот грязный метод, где метод экземпляра перемещает кадр вверх и перезаписывает свою собственную запись локальных элементов. Не рекомендую. (например, на самом деле нет. Я даже не уверен, что это делает. Что происходит со старым экземпляром? Я недостаточно знаю о кадрах ...). На самом деле, я публикую это только потому, что все говорят, что это невозможно, хотя на самом деле это просто смехотворно плохая форма. ; -)

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
3 голосов
/ 09 сентября 2013

Вы можете поместить неизменный объект в изменяемый контейнер; списки самые простые.

Этот код печатает 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       # 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`)

На практике вы должны структурировать свои данные так, чтобы вышеуказанный «трюк» был излишним. Примеры не должны использоваться напрямую, но должны помочь вам понять, что делать.

3 голосов
/ 16 июля 2009

Вероятно, было бы проще создать класс, который реализует методы int и переносит внутреннее целое число.

0 голосов
/ 15 июля 2017

У меня была похожая проблема сегодня, и я предложил класс IterInt, который позволяет увеличивать или уменьшать на месте с помощью «+» и «-» декораторов.

Использование:

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, который я использую, имеет функцию «addCommand», которая может принимать индекс для вставки.

Рассмотрим этот псевдокод, где в меню есть команды от 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]
0 голосов
/ 16 июля 2009

Да, короткий ответ таков: целые числа неизменны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...