16

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
4

7 回答 7

13

int 是不可变的,因此如果您想要一个“可变 int”,则必须使用所有 int 方法构建自己的类

于 2009-07-16T04:10:55.603 回答
8

您可以将 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

于 2015-02-27T05:09:32.073 回答
6

如果您绝对必须让该代码工作,这里有一个脏方法,其中一个实例方法向上移动一个框架并覆盖它自己的本地条目。不推荐。(就像,真的没有。我什至不确定那是做什么的。旧实例会发生什么?我对帧了解不够......)。真的,我发布这个只是因为每个人都说这是不可能的,而实际上它只是一种可笑的糟糕形式。;-)

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
于 2009-07-16T23:44:29.413 回答
4

创建一个实现 int 方法并包装内部整数的类可能会更容易。

于 2009-07-16T04:10:36.447 回答
4

您可以将不可变对象放入可变容器中;列表是最简单的。

此代码打印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`)

在实践中,您应该对数据进行结构化,以便上述“技巧”是多余的。这些示例不应直接使用,但应帮助您弄清楚该怎么做。

于 2013-09-09T14:24:02.957 回答
0

是的,简短的回答是,整数是不可变的。

于 2009-07-16T04:11:45.523 回答
0

我今天遇到了类似的问题,并提出了一个名为 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”函数,它可以获取要插入的索引。

考虑这个伪代码,其中 menu 有命令 a 到 g,类似于 menu = [a, f, g],我想在索引 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]
于 2017-07-14T23:05:09.590 回答