是的,cpython重用了id()
值。 。
这是明确记载:
返回对象的“身份”。这是一个整数,可以保证在 唯一且恒定
大胆强调我的。仅当对象 存在时 ,id才是唯一的。没有剩余引用的对象将从内存中删除,从而允许将该id()
值重新用于另一个对象,因此使用了非重叠生命周期的 措辞。
请注意,这仅适用于cpython,这是python.org提供的标准实现。还有其他Python实现,例如IronPython,Jython和PyPy,它们对实现方式id()
都有自己的选择,因为它们每个都可以对如何处理内存和对象生存期做出不同的选择。
要解决您的特定问题:
>>> id(1234)
4546982768
id(4321) 4546982768
的1234
字面创建一个新的整数对象,为此id()
产生一个数值。由于没有对该int
值的进一步引用,因此将其再次从内存中删除。但是使用不同的整数文字再次执行相同的表达式,很可能会看到相同的id()
值(运行垃圾回收破坏循环引用可能会释放更多的内存,因此您也 id()
再次看到相同的值。
因此它 不是随机的 ,但在cpython中是内存分配算法的函数。
例如,先记录一个对象引用,然后再检查它:
import weakref
# record
object_ref = weakref.ref(some_object)
# check if it's the same object still
some_other_reference is object_ref() # only true if they are the same object
弱引用不会保留该对象还活着,但如果它 是 活的那么object_ref()
将返回它(它会返回None
其他)。
您可以使用这种机制来生成真正唯一的标识符,请参见下文。
一旦所有对一个对象的引用都消失了,该对象上的引用计数就会降为0,然后在该位置被删除。
仅需要垃圾回收即可破坏 循环引用 ,即仅互相 引用的 对象,而无需进一步引用循环。因为这样的一个循环在没有帮助的情况下永远不会达到0的引用计数,因此垃圾收集器会定期检查这种循环并中断其中一个引用以帮助从内存中清除那些对象。
因此,通过删除对对象的所有引用,可以使它从内存中删除(释放)。如何实现取决于对象的引用方式。你可以要求译员告诉你哪些对象引用与给定对象gc.get_referrers()
的功能,但考虑到不给你变量名 。它为您提供对象,例如字典对象,该对象是将__dict__
对象引用为全局对象的模块的属性,等等。对于完全在您控制之下的代码,最多gc.get_referrers()
用作提醒自己从何处引用对象的工具当您编写代码删除这些代码时。
如果必须在 Python应用程序 的生存期内具有唯一的标识符,则必须实现自己的工具。如果您的对象是可 哈希的 并且支持弱引用,那么您可以使用WeakKeyDictionary
实例将任意对象与UUID关联:
from weakref import WeakKeyDictionary
from collections import defaultdict
from uuid import uuid4
class UniqueIdMap(WeakKeyDictionary):
def __init__(self, dict=None):
super().__init__(self)
# replace data with a defaultdict to generate uuids
self.data = defaultdict(uuid4)
if dict is not None:
self.update(dict)
uniqueidmap = UniqueIdMap()
def uniqueid(obj):
"""Produce a unique integer id for the object.
Object must me *hashable*. Id is a UUID and should be unique
across Python invocations.
"""
return uniqueidmap[obj].int
这仍然产生整数,但因为他们是他们不太UUID的 保证 是唯一的,但可能你会 永远 在遇到同样的ID 你的 一生是不是被陨石击中小。
这样,即使对于具有非重叠生命周期的对象,这也会为您提供唯一的ID:
>>> class Foo:
... pass
...
>>> id(Foo())
4547149104
>>> id(Foo()) # memory address reused
4547149104
>>> uniqueid(Foo())
151797163173960170410969562162860139237
>>> uniqueid(Foo()) # but you still get a unique UUID
188632072566395632221804340107821543671