dict开箱时内部发生了什么?

时间:2018-06-28 08:37:25

标签: python python-3.x iterable-unpacking

我正在尝试弄清字典的内容时调用什么方法,以便我可以自定义流程?

我想以下hack会向我展示在select * from t42 where MYCOLUMN <> '*'; ID MYCOLUMN ---------- -------------------- 2 The*is embedded 3 The * is embedded 4 *.* 5 The*.*is embedded 6 The *.* is embedded 7 No asterisk 6 rows selected. 实例的任何方法访问期间调用的方法:

Dict

但是下面的会话显示没有调用任何方法来执行dict拆包?

class Dict(dict):
    def __getattribute__(self, name):
        print(name)
        return super().__getattribute__(name)

那么这里实际上发生了什么?如何自定义拆包过程?


修改

我认为问题不是the other one的重复。即使实现了该问题答案中提到的所有特殊方法,在dict拆包过程中都不会调用它们。

In [1]: d = Dict(a=1)
__class__
__class__

In [2]: {**d}
Out[2]: {'a': 1}

您不会看到任何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} 行被称为。所以我的问题仍然没有答案。

FWIW,python版本是Python 3.6.5。

1 个答案:

答案 0 :(得分:1)

这是a bug in how Python handled dict subclasses that was fixed in late September, 2018

the fix之前,使用特定于dict的具体C API方法(绕过所有动态定义的覆盖)将任何dict子类转换为普通的dict。修复之后,代码将检查__iter__(相当于C的tp_iter)是否已被覆盖,如果是,则不对dict使用快速路径。检查__iter__是有点错误的IMO(实际上使用的唯一两种方法是keys__getitem__),但是如果您要覆盖keys ,您可能还应该覆盖__iter__,所以这样做并不是一件麻烦的事(在许多情况下,一个可能是另一个的别名,或者最多是一个苗条的包装,这取决于{{1 }}返回迭代器或视图对象。

鉴于错误修正的最新程度,您需要升级Python以获得好处。 3.6.7和3.7.1是它们各自次要版本中包含修复程序的第一个微型发行版,因此,升级到其中一个应该可以使您的代码正常工作。