Python - 如何区分指向同一对象的两个列表元素?
我有一个环形结构,下面是我实现的方式(参考了一个食谱):
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]的对象身份和哈希值,似乎Python在重复使用这4个对象。
我该怎么告诉Python,我真的想把第二个4(现在是x[4])放在最上面呢?
抱歉问这么基础的问题……这就是自学的初学者的一些困扰。
谢谢,
迈克
===编辑===
顺便说一下,我把类中的setTop方法去掉了。我本来是觉得“嘿,这样做很酷,可能会有用”而加上的。根据回答(特别是“有什么区别”,说得很对)和我自己使用这个结构的经验来看,这个方法其实很糟糕,根本不支持我的任何用例。
换句话说,添加一些东西只是因为我能做到,而不是为了满足需求 = 失败。
7 个回答
在Python的Cpython版本中,对于一些小整数(大约是从-5到255之间的数字),它有一个“整数缓存”。这意味着这些数字会重用同一个对象,也就是说,所有的4都是同一个值为4的整数对象。这样做是为了减少创建新对象的需要。
如果你想绕过这个限制,有几种方法:
- 你可以使用长整型(比如写4L而不是4)。Python对长整型不使用缓存。(你也可以使用浮点数,因为它们同样不被缓存。)不过,如果你对这些数字进行大量数学运算,可能会影响性能。
- 你可以把每个数字放在一个列表或元组里(这样做比较方便,因为语法简单,虽然比使用长整型或浮点数要多一些语法)。
- 你可以创建一个自己的对象来包装这个整数。这个对象会有和整数一样的方法(所以在数学运算、比较、打印等方面都能像整数一样工作),但每个实例都是独一无二的。
我个人比较喜欢在这种情况下使用长整型。你可以在构造函数中轻松地把整数转换为长整型,并在任何添加项目的方法中进行转换。
如果你已经确定想要第二个选项,那就这样做:
x = Ring([1,2,3,4,4])
x.setTop(4)
x.turn()
x.setTop(4)
你可以改进setTop()这个函数,让它接受一个额外的参数,然后在里面处理这个参数。
来自《学习Python,第4版》第6章:
从概念上讲,每当你在脚本中通过运行一个表达式生成一个新值时,Python都会创建一个新的对象(也就是一块内存)来表示这个值。为了提高效率,Python内部会缓存并重用某些不可改变的对象,比如小整数和字符串(比如每个0其实并不是一块新的内存——关于这种缓存行为我们稍后会详细讲)。不过,从逻辑上看,每个表达式的结果值就像是一个独立的对象,而每个对象又是一个独立的内存块。
问题是……
if x[3] is x[4]:
print "What's the difference?"