Python:具有唯一ID的相同字符串(或数字)?

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' >>

Python经过了极好的优化,但我有一个案例想解决它。对于较小的数字和字符串,python会自动将多个对象折叠为一个。例如:

>>> 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)