Python 的 `dict` 无法识别自己的密钥

Python's `dict` doesn't recognize its own key

编辑 2:最后我能够制作 MWE:

from typing import Generic, TypeVar
T = TypeVar('T')

class Cache:
    __dict = {}

    @classmethod
    def add(cls, item):
        cls.__dict[item] = (item, [item, item, item, {item: item}])
        print('On setting:', item in cls.__dict)

    def __init_subclass__(cls, **kwargs):
        Cache.add(cls)


class Class(Cache, Generic[T]):
    pass

d = Cache._Cache__dict
tp = list(d)[0]
print('On checking:', tp in d)

在python3.6中输出为:

On setting: True
On checking: False

而在 3.8 中是:

On setting: True
On checking: True

如果这还不够奇怪,如果我从 Generic[T] 中删除继承,一切都很好。

原版

我正在使用 Python 3.6,当我尝试从字典中获取键时得到 KeyError

# d: Dict[type, Any]

tp = list(d.keys())[0]
d[tp]
# KeyError: ...

意思是从字典中取出的键导致了这个异常。请注意 d 只有一个条目。键类型是一个以 GenericMeta 作为其元类的类型对象,所以这可能是问题所在吗?

我使用调试器验证了以下属性:

  1. id(tp)多次调用相同
  2. hash(tp)多次调用相同
  3. tp is list(d.keys())[0]
  4. tp == list(d.keys())[0]
  5. len(d) == 1

编辑:

  1. print(type(tp)) # <class 'typing.GenericMeta'>
  2. print(type(tp)) # <class 'dict'>

我的问题是:造成这种行为的原因可能是什么?

由于某些软件包的兼容性问题,我无法更新 python 版本,所以请不要告诉我更新,除非它是一个已在更高版本中解决的已知错误。

这是一个初始化顺序问题。

在 Python 3.6 上,Classtyping.GenericMeta 的一个实例。 typing.GenericMeta__new__ 中执行重要的初始化,但该初始化只能开始一次 type.__new__ returns 要初始化的东西。 type.__new__ 负责调用 __init_subclass__,因此您的 __init_subclass__ 在任何 GenericMeta 初始化发生之前运行。

当您的 __init_subclass__Class 添加到字典时,尚未执行 ==hash 正常工作所需的初始化。此操作最终使用无效的散列。后来,一旦初始化完成,查找使用正确的散列,找不到 Class.

在后来的 Python 版本中,整个通用 class 实现被完全改变了。 typing.GenericMeta 不再存在。