編輯 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)
在 python 3.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作為它的元類,所以這可能是問題嗎?
我使用除錯器驗證了以下屬性:
id(tp)在多個呼叫中是相同的。hash(tp)在多個呼叫中是相同的。tp is list(d.keys())[0]tp == list(d.keys())[0]len(d) == 1
編輯:
print(type(tp)) # <class 'typing.GenericMeta'>print(type(tp)) # <class 'dict'>
我的問題是:這種行為的原因可能是什么?
I can't update the python version due to some of the packages' compatibility issues, so please don't tell me to update unless it's a known bug that's solved in a later version.
uj5u.com熱心網友回復:
這是一個初始化順序問題。
在 Python 3.6 上,Class是typing.GenericMeta. typing.GenericMeta在 中執行重要的初始化__new__,但該初始化只能開始一次type.__new__回傳要初始化的內容。type.__new__負責呼叫__init_subclass__,因此您__init_subclass__可以在任何GenericMeta初始化發生之前運行。
當您__init_subclass__添加Class到字典,初始化必要的==和hash正確尚未完成的作業。此操作最終使用了無效的哈希值。稍后,一旦初始化完成,查找使用正確的散列并且找不到Class。
在后來的 Python 版本中,整個泛型類的實作完全改變了。typing.GenericMeta不復存在。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/402270.html
標籤:python dictionary python-3.6
下一篇:檢查存盤大值的映射中是否存在鍵
