在 dict 解包期间内部发生了什么?
What happened internally during dict unpacking?
我想知道解压字典时调用了哪些方法,以便我可以自定义过程?
我想下面的 hack 会向我展示在 Dict
实例的任何方法访问期间调用的方法:
class Dict(dict):
def __getattribute__(self, name):
print(name)
return super().__getattribute__(name)
但是下面的session显示没有调用dict解包的方法?
In [1]: d = Dict(a=1)
__class__
__class__
In [2]: {**d}
Out[2]: {'a': 1}
那么这里到底发生了什么?如何自定义解包过程?
编辑
我不认为这个问题与 the other one 重复。即使实现了该问题的答案中提到的所有特殊方法,在 dict 解包期间也没有调用它们。
In [66]: class Dict(dict):
...: def __getattribute__(self, name):
...: print(name)
...: return super().__getattribute__(name)
...: def keys(self):
...: print("hello")
...: return super().keys()
...: def __getitem__(self, key):
...: print("hello")
...: return super().__getitem__(key)
...: def __len__(self):
...: print("hello")
...: return super().__len__()
...: def __iter__(self):
...: print("hello")
...: return super().__iter__()
...:
In [67]: d = Dict(a=1)
__class__
__class__
In [68]: {**d}
Out[68]: {'a': 1}
您可以看到没有任何 print
行被调用。所以我的问题仍然没有答案。
FWIW,python 版本是 Python 3.6.5。
这是 a bug in how Python handled dict
subclasses that was fixed in late September, 2018。
在 the fix 之前,任何 dict
子类都使用具体的 dict
-特定的 C API 方法(绕过所有动态定义的覆盖)。修复后,代码检查 __iter__
(好吧,C 等价物,tp_iter
)是否已被覆盖,如果是,它不会使用 dict
的快速路径。检查 __iter__
有点错误 IMO(它实际上 使用 的唯一两种方法是 keys
和 __getitem__
),但是如果你重写 keys
,你可能也应该重写 __iter__
,所以这样做并不是什么大麻烦(在许多情况下,一个可以是另一个的别名,或者至多是一个 slim wrapper,这取决于是否keys
returns 迭代器或视图对象)。
鉴于错误修复是最近的,您需要升级 Python 才能获得好处。 3.6.7 和 3.7.1 是它们各自的次要版本行中第一个包含修复程序的微版本,因此升级到任何一个都应该可以使您的代码正常工作。
我想知道解压字典时调用了哪些方法,以便我可以自定义过程?
我想下面的 hack 会向我展示在 Dict
实例的任何方法访问期间调用的方法:
class Dict(dict):
def __getattribute__(self, name):
print(name)
return super().__getattribute__(name)
但是下面的session显示没有调用dict解包的方法?
In [1]: d = Dict(a=1)
__class__
__class__
In [2]: {**d}
Out[2]: {'a': 1}
那么这里到底发生了什么?如何自定义解包过程?
编辑
我不认为这个问题与 the other one 重复。即使实现了该问题的答案中提到的所有特殊方法,在 dict 解包期间也没有调用它们。
In [66]: class Dict(dict):
...: def __getattribute__(self, name):
...: print(name)
...: return super().__getattribute__(name)
...: def keys(self):
...: print("hello")
...: return super().keys()
...: def __getitem__(self, key):
...: print("hello")
...: return super().__getitem__(key)
...: def __len__(self):
...: print("hello")
...: return super().__len__()
...: def __iter__(self):
...: print("hello")
...: return super().__iter__()
...:
In [67]: d = Dict(a=1)
__class__
__class__
In [68]: {**d}
Out[68]: {'a': 1}
您可以看到没有任何 print
行被调用。所以我的问题仍然没有答案。
FWIW,python 版本是 Python 3.6.5。
这是 a bug in how Python handled dict
subclasses that was fixed in late September, 2018。
在 the fix 之前,任何 dict
子类都使用具体的 dict
-特定的 C API 方法(绕过所有动态定义的覆盖)。修复后,代码检查 __iter__
(好吧,C 等价物,tp_iter
)是否已被覆盖,如果是,它不会使用 dict
的快速路径。检查 __iter__
有点错误 IMO(它实际上 使用 的唯一两种方法是 keys
和 __getitem__
),但是如果你重写 keys
,你可能也应该重写 __iter__
,所以这样做并不是什么大麻烦(在许多情况下,一个可以是另一个的别名,或者至多是一个 slim wrapper,这取决于是否keys
returns 迭代器或视图对象)。
鉴于错误修复是最近的,您需要升级 Python 才能获得好处。 3.6.7 和 3.7.1 是它们各自的次要版本行中第一个包含修复程序的微版本,因此升级到任何一个都应该可以使您的代码正常工作。