目前发现这样一个问题:
自定义一个 dict
子类,并且实现自定义 __bool__
方法后 json.dumps()
会产生和预期不符的结果
话不多说,上代码
import json
class InnerDict(dict):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def __bool__(self):
# 原始这里的逻辑是只要字典为空才返回 False,非空都返回 True
# 但是如果改掉比如这里所有都返回 False
return False
dct = InnerDict()
dct["hello] = "world"
print(dct) # 到这里都没有问题
json.dumps(dct, ensure_ascii=False, indent=4) # 但是这里,dumps 的结果就是 {}
原因分析:
在 json
库 encoder.py
文件中 _make_iterencode
方法内有个闭包的方法 _iterencode_dict
在这方法中第一件事去判断 dct
是否为空,用了
if not dct:
yield '{}'
return
截图在这里 https://www.v2ex.com/i/5Xjw6YFt.jpeg
但是问题就在这里,这里会调用 __bool__
判断,但是 __bool__
的逻辑已经被改了,所以在上面的代码里这里一直为 {}
而且追踪了 _iterencode_dict
方法,发现三处调用处均判断了 dct
对象为 dict
这里的 if not dct
仅仅做了判断 dct
是否为空 dict
目前就是这么个情况,不知道这算不算一个 bug
1
ruanimal 64 天前
这不算 bug 吧。。
而且你这个继承违反了里氏代换原则 |
2
acmore 64 天前
如果 `_iterencode_dict` 只管按自己的逻辑去判断是否为空,而不管你怎么实现 `__bool__`,这才是一个 Bug,因为实际上对 `__bool__` 的重载是无效的。
你没有正确实现 `__bool__` 的功能,自然也得不到期待的结果。 |
3
zmaplex 64 天前 via Android
不算,我认为你破坏了设计上的传递性。
|
![]() |
4
Vinty 64 天前
对象为空,所以 dump 也是空的,这很符合逻辑啊
|
![]() |
5
ofooo 64 天前
不要弄 dict 的子类,确实有 bug,python 猫公众号前几天还讲过。
不要弄 python 官方类的子类的魔法函数,他继承顺序有一定的不一致性 |
![]() |
6
ofooo 64 天前
不过感觉你这个是自作自受吧。。。。人家这个逻辑没问题啊
|
![]() |
7
xuboying 64 天前
看了半天没理解 op 觉得哪里是 bug ?是对那个 if 判断的条件有异议么? op 期望是怎样的结果。
|
![]() |
8
cz5424 64 天前 via iPhone
这个问题类似于,我修改了支付宝客服端,加了个一百万,但是我买不了东西
|
![]() |
9
Wincer 64 天前 via Android
楼主意思是 if not dct 应该改成 if dct is not {}?
|
![]() |
10
SjwNo1 64 天前
那就再改 __bool__ 知道你满意为止哈哈
|
![]() |
11
mringg 64 天前
我想说人生已经够难了,不要难为自己了,就用些基本的用法不好么
|
![]() |
12
no1xsyzy 64 天前
dict 的 __bool__ 含义就是这个 dict 是否为空
_iterencode_dict 说:既然你说它是空,那它就是空咯,不反驳,'{}' 来 |
![]() |
13
timothyqiu 64 天前
说白了就是 garbage in, garbage out
|
![]() |
14
cnrting 64 天前 via iPhone
都用 python 了何苦再为难自己
|
![]() |
15
lithbitren 64 天前
只有在算法题里写字典树的时候会继承字典,其他情况下原则上都不会继承这些基础数据结构
|
16
krixaar 64 天前
这是不是可以类比成后端偷偷改了接口返回值,前端崩了说是前端有 bug ?
|