Python:具有唯一ID的相同字符串(或数字)?
Python经过了极好的优化,但我有一个案例想解决它。对于较小的数字和字符串,python会自动将多个对象折叠为一个。例如:Python:具有唯一ID的相同字符串(或数字)?,python,string,Python,String,Python经过了极好的优化,但我有一个案例想解决它。对于较小的数字和字符串,python会自动将多个对象折叠为一个。例如: >>> a = 1 >>> b = 1 >>> id(a) == id(b) True >>> a = str(a) >>> b = str(b) >>> id(a) == id(b) True >>> a += 'foobar' >>
>>> a = 1
>>> b = 1
>>> id(a) == id(b)
True
>>> a = str(a)
>>> b = str(b)
>>> id(a) == id(b)
True
>>> a += 'foobar'
>>> b += 'foobar'
>>> id(a) == id(b)
False
>>> a = a[:-6]
>>> b = b[:-6]
>>> id(a) == id(b)
True
我有一个例子,根据对象的Python ID比较对象。这是非常好的工作,除了少数情况下,我遇到小的数字。有人知道如何关闭特定字符串和整数的优化吗?类似于anti-intern()的东西?如果不重新编译自己的CPython版本,就无法关闭它 但是,如果您想拥有相同小整数的“单独”版本,可以通过维护与该对象关联的您自己的id(例如
uuid4
)来实现
因为int和string是不可变的,所以没有明显的理由这样做——如果您根本不能修改对象,那么您不应该关心您是否拥有“原始”或副本,因为没有任何用例可以让它产生任何不同
相关:您不应该依赖这些对象作为不同的对象。在不修改和重新编译Python的情况下,无法关闭此行为,并且它应用于哪些特定对象可能会在不通知的情况下更改。当然,这是可以做到的,但这绝对不是一个好主意:
#
Z =1
class MyString(string):
def __init__(self, *args):
global Z
super(MyString,
self).__init__(*args)
self.i = Z
Z += 1
>>> a = MyString("1")
>>> b = MyString("1")
>>> a is b
False
顺便说一句,要比较对象是否具有相同的id
,只需使用a is b
,而不是id(a)==id(b)
返回对象的“标识”。这是一个整数,保证该对象在其生存期内唯一且恒定。两个生命周期不重叠的对象可能具有相同的id()值
CPython实现细节:这是内存中对象的地址
所以它保证是唯一的,它必须是一种判断两个变量是否绑定到同一个对象的方法
在本文中,Alex Martelli说,CPython实现并不是权威的Python,其他正确的Python实现可以而且确实在某些方面表现不同,并且(PLR)是Python最接近最终规范的东西
书中也说了同样的话:
每个对象都有一个标识、一个类型和一个值。对象的标识在创建后不会改变;您可以将其视为对象在内存中的地址。“is”运算符比较两个对象的标识;函数的作用是:返回一个表示其标识的整数(当前实现为其地址)
语言引用没有说它保证是唯一的。它还表示(re:对象的生存期):
物体永远不会被明确摧毁;但是,当它们变得无法访问时,可能会被垃圾收集。一个实现可以推迟垃圾收集或完全忽略垃圾收集——只要没有收集到仍然可以访问的对象,垃圾收集是如何实现的是实现质量的问题
以及:
CPython实现细节:CPython目前使用一种引用计数方案,该方案具有(可选)延迟检测循环链接垃圾的功能,它会在无法访问大多数对象时立即收集这些对象,但不能保证收集包含循环引用的垃圾。有关控制循环垃圾收集的信息,请参阅gc模块的文档。其他实现的行为不同,CPython可能会发生变化。当对象变得不可访问时,不要依赖于对象的立即终结(例如:始终关闭文件)
这并不是一个真正的答案,我希望这会是一个决定性的结果。但我现在不想删除它,我已经引用了
我将改变你的前提:python将自动将多个对象折叠为一个。
-不,不会,它们从来都不是多个对象,它们不可能是,因为它们具有相同的id()
如果id()是Python关于两个对象是相同的还是不同的最终答案,那么你的前提是错误的——这不是优化,而是Python世界观的一个基本部分。好吧,既然没有人给出有用的回复,我就告诉你我最后做了什么 首先,给可能有一天读到这篇文章的人一些友好的建议。这是不建议正常使用,所以如果你正在考虑它,问问自己,如果你真的有一个很好的理由。有很好的理由,但它们是罕见的,如果有人说没有,他们只是没有认真思考 最后,我在所有对象上使用了pickle.dumps(),并传入了输出,而不是真正的对象。另一方面,我检查了id,然后使用pickle.loads()还原对象。这个解决方案的优点在于它适用于所有类型,包括None和Boolean
>>> a = 1
>>> b = 1
>>> a is b
True
>>> aPickled = pickle.dumps(a)
>>> bPickled = pickle.dumps(b)
>>> aPickled is bPickled
False
>>> aUnPickled = pickle.loads(aPickled)
>>> bUnPickled = pickle.loads(bPickled)
>>> aUnPickled is bUnPickled
True
>>> aUnPickled
1
这一版本解释了wim对未来更激进拘留的担忧。它将使用更多的内存,这就是我最初丢弃它的原因,但可能更能证明未来
>>> class Wrapper(object):
... def __init__(self, obj):
... self.obj = obj
>>> a = 1
>>> b = 1
>>> aWrapped = Wrapper(a)
>>> bWrapped = Wrapper(b)
>>> aWrapped is bWrapped
False
>>> aUnWrapped = aWrapped.obj
>>> bUnwrapped = bWrapped.obj
>>> aUnWrapped is bUnwrapped
True
或类似pickle答案的版本(wrap+pickle=wrappe):
文字值在CPython中实现,因此它们具有相同的id值。一个对象,多个名称感谢所有信息。我们可以同意在Python是否折叠多个对象的问题上存在分歧。我很确定这正是在C级发生的事情。为每个对象创建uuid不允许分析引用,这是本练习的重点。这似乎不是一个可伸缩的解决方案。如果我们不能依赖ID,那么我们也不应该在Python中使用“is”。@aviso:对于这些对象,您确实不应该使用
is
is。“is”用于比较两个对象是否相同,这正是本练习的重点;aPickled是aPickledAgain也给出了False
class Wrapple(object):
def __init__(self, obj):
self.obj = obj
@staticmethod
def dumps(obj):
return Wrapple(obj)
def loads(self):
return self.obj
aWrapped = Wrapple.dumps(a)
aUnWrapped = Wrapple.loads(a)