python - 如何在整个程序的生命周期中唯一标识Python中的类

标签 python python-3.x

问题

如何在整个程序的生命周期中唯一标识Python中的类?我对内置类型和用户定义类型都感兴趣。 id 不合适,因为:

[id] returns the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

可能吗?

具体用例

我有一个字典,其中字符串作为键,Python 的类型/类作为值。例如:

{'tid': int, 'name': str, 'color': str}

问题是唯一标识字符串和类型的组合并将其用作比较的基础。因此,字典 {'tid': int, 'name': str, 'color': str} 和字典 {'tid': float, 'name': str, 'color' : str} 应该被判定为不相等。类似地, {'tid': int, 'name': str, 'color': str}{'tid': int, 'name': str, 'colour': str }.

陷阱

此外,如果名称和类型经过哈希处理并存储结果,则比较应该有效(因为比较整数比比较字典更快)。例如:

def hash_heading(dct):
    s = ''
    for k, v in OrderedDict(dct).items():
        s += k + str(id(v))
    return hash(s)

这会带来这样的风险:两个具有不相交生命周期的类 A 和 B 会被分配相同的 id(以防 A 在声明 B 之前被销毁),因此检查会通过。

<小时/>


[1]https://docs.python.org/3/library/functions.html#id

最佳答案

首先:内置类型和自定义 Python 类型都只是 Python 对象。就 id() 而言,您无需担心任何差异。

您确实想使用id()来跟踪类(class)。因为如果 id() 已更改,则意味着您不再拥有相同的类。反之亦然,因为 id() 值可以重复用于生命周期不重叠的对象,因此具有相同的 id() 值并不意味着您可以仍然有相同的对象。

类应该是单例的。类很少被重新定义,因为大多数代码会在模块级别定义它们,并且模块也是单例(它们位于 sys.modules 中并且仅加载一次)。

此外,具有不同 ID 的类不是同一个类。它可能具有相同的名称,也可能位于同一模块中,但您不能使用其中一个来断言另一个的实例属于同一类型。您不应该尝试在 Python 的整个生命周期中跟踪类并忽略它们的 id() 值。

一个快速演示来说明为什么不能:

>>> import types
>>> module.Foo = type('Foo', (), {'__module__': module.__name__})
>>> module.Foo
<class 'foo.Foo'>
>>> id(module.Foo)
140646171069480
>>> foo_instance = module.Foo()
>>> isinstance(foo_instance, module.Foo)
True
>>> module.Foo = type('Foo', (), {'__module__': module.__name__})  # new class, same name, same location!
>>> id(module.Foo)
140646170684440
>>> isinstance(foo_instance, module.Foo)
False
>>> type(foo_instance)
<class 'foo.Foo'>
>>> type(foo_instance) is not module.Foo
True

foo_instance 实例是类 Foo 的实例,但它是它的第一个 Foo 类是一个实例。通过创建一个新的 Foo 类,id() 随之改变,但它告诉您我们现在有一个不同的对象,一个独特的新类对象。

如果您只跟踪 id(),如果要删除对原始 Foo 的所有引用,则该对象会从内存中删除,然后新的 Foo 已创建,它可以具有相同的 id(),因为 id() 值可以是重新使用。因此,您可以拥有一个具有相同 id() Foo。这并不重要,因为如果没有更多引用,旧的 Foo 只能从内存中删除。实例保存对其类的引用,因此如果存在类的实例,则该类将继续保留在内存中。

如果您所做的只是比较字典中包含的类,那么您根本不需要诉诸 id() 测试,因为仅进行类相等性测试对于相同的对象,永远返回 true。仅当两个引用都指向同一个类对象时,reference_to_class == other_reference_to_class 才为True;该测试本质上与 reference_to_class is other_reference_to_class 相同。字典保存了对其所有内容的引用,使这些内容保持活力。通过将类型存储在字典中,您可以确保它们的 id() 值也不会更改。

您链接到的帖子并未询问类的id()。他们正在讨论实例id()值;它讨论了诸如具有不同 id() 值的多个实例之类的问题,并且快速连续创建和丢弃实例并不能保证第一个实例的 id() 被重用第二个。

关于python - 如何在整个程序的生命周期中唯一标识Python中的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51503591/

相关文章:

python - Gunicorn 线程没有任何区别

python - 从 Raspberry Pi 捕获 jpeg 图像并将其发送到 PC socket python?

html - 使用 xpath 从 ul 中选择 li 元素

python - 为什么我的代码会引发 AttributeError 而不是 ValueError

Python 网络抓取工具在输入 520 个 url 时卡住。它出什么问题了?

python - 如何在python中扩展一个类?

python - 更改 Gtk.Button 标签的样式/字体

python - 如何返回列表中出现次数最多的元素?

python - 如何在 python 中获取除服务器时区 (UTC) 之外的用户本地时区?

python - 使用 sleep() 时 Python 运动中的代码不流畅