Python - 如何区分指向同一对象的两个列表元素?

时间:2010-09-28 16:16:15

标签: python

我有如下实现的Ring结构(基于我找到的食谱配方):

class Ring(list):

    def turn(self):
        last = self.pop(0)
        self.append(last)

    def setTop(self, objectReference):
        if objectReference not in self:
            raise ValueError, "object is not in ring"

        while self[0] is not objectReference:
            self.turn()

说我做了以下事情:

x = Ring([1,2,3,4,4])
x.setTop(4)

我的代码将始终将前4个(当前为x [3])设置为x [0]。似乎(通过x [3]和x [4]之间的对象标识和哈希id测试)Python正在重用4对象。

我如何告诉Python我真的希望第二个4(当前x [4])位于顶部?

为基本问题道歉......成为一名自学成才的初学者之一。

谢谢,

麦克

=== EDIT ===

为了它的价值,我从课堂上删除了setTop方法。我已将它添加到标准配方中,认为“嘿,这将是整洁的,可能是有用的。”作为答案(特别是“有什么不同”,这是现场的)和我自己使用结构展示的经验,这是一个糟糕的方法,不支持我的任何用例。

换句话说,添加一些东西,因为我可以而不是满足需要=失败。

7 个答案:

答案 0 :(得分:4)

来自学习Python,第4版 - 第6章:

  

至少在概念上,每次通过运行脚本在脚本中生成新值   表达式,Python创建一个新对象(即一大块内存)来表示它   值。在内部,作为优化,Python缓存并重用某些类型的un-   可变对象,例如小整数和字符串(每个0都不是新的一块   内存 - 稍后更多关于此缓存行为)。但是,从逻辑的角度来看,它   就好像每个表达式的结果值是一个不同的对象,每个对象都是一个   独特的记忆。

问题是......

if x[3] is x[4]:
    print "What's the difference?"

答案 1 :(得分:2)

如果你知道你想要第二个,那就去做

x = Ring([1,2,3,4,4])
x.setTop(4)
x.turn()
x.setTop(4)

您可以增强setTop()以获取其他参数并在内部执行。

答案 2 :(得分:1)

Cpython对于小整数有一个“整数缓存”,因此从-5到255(可能因版本或Python实现而异)的值会为给定值重用相同的对象。也就是说,所有4都是相同的 int对象,其值为4.这样做是为了减少创建对象的必要性。

有几种方法可以解决这个问题。

  • 您可以使用长整数(例如,写入4L而不是4)。 Python不会将长缓存用于长整数。 (你也可以使用浮点数,因为它们同样没有被缓存。)但是,如果你用数字做了很多数学计算,这可能会导致一些性能损失。
  • 你可以将每个项目包装在一个列表或元组中(相当方便,因为它有简单的语法,尽管它比长整数或浮点数更多的语法)。
  • 您可以创建自己的对象来包装整数。该对象将具有与整数相同的所有方法(因此它在数学,比较,打印等方面类似于整数)但每个实例都是唯一的。

我个人喜欢在这种情况下使用长注。您可以在构造函数中以及添加项目的任何方法中轻松地将整数转换为long。

答案 3 :(得分:1)

听起来你总是想要至少转一次,对吗?如果是这样,请重写您的setTop方法,如下所示:

def setTop(self, objectReference):
    if objectReference not in self:
        raise ValueError, "object is not in ring"

    self.turn()
    while self[0] is not objectReference:
        self.turn()

然后它在预期状态之间循环:

>>> x = Ring([1,2,3,4,4])
>>> x
[1, 2, 3, 4, 4]
>>> x.setTop(4)
>>> x
[4, 4, 1, 2, 3]
>>> x.setTop(4)
>>> x
[4, 1, 2, 3, 4]
>>> x.setTop(4)
>>> x
[4, 4, 1, 2, 3]

答案 4 :(得分:0)

我也不太了解,但我猜数字,即使是对象,在代码的不同点使用时也是相同的对象。 我为什么这么认为?看:

>>> type(2)
<type 'int'>
>>> type(lambda x:x)
<type 'function'>
>>> 2 is 2
True
>>> (lambda x: x) is (lambda x: x)
False

创建两次时,2个对象不相同。但数字不是由你创造的,它们已经存在。从另一个4给一个4个不同的对象是没有意义的。至少我没有看到一个。

答案 5 :(得分:0)

对于小数字,python将预先制作一个对象缓存,以避免制作新对象的成本。它们将具有相同的对象标识。 Java也是这样做的。你需要一种方法来避免这样做。

答案 6 :(得分:0)

Python重用小整数和短字符串。据我所知,没有办法解决这个问题 - 你必须与此相处以及setTop仅在第一场比赛之前旋转的事实。我想你可以添加一个optinal参数n = 1,然后转到n匹配。但那不是重点,不是吗?

无关紧要,请考虑一下:

>>> class Point(object):
...     def __init__(self, x, y):
...         self.x, self.y = x, y
...     def __eq__(self, other):
...         return (self.x == other.x and self.y == other.y)
... 
>>> a_ring = Ring(Point(1, 2), Point(15, -9), Point(0, 0))
>>> a_ring.seTop(Point(15, -9))
Traceback ...
...
ValueError: object not in ring

不是它应该如何工作,是吗?您应该使用while self[0] != objectReference(这是一个误导性的名称)来避免这种情况。