背景
这几天在写python脚本的时候,需要将class对象转化为json字符串,作为参数进行接口调用。写好运行后异常,异常信息如下:
AttributeError: ‘mappingproxy’ object has no attribute ‘dict’
网上查找资料说是写法不对,建议我一层一层手动遍历。
如下是我的写法:
config_json = json.dumps(configuration.__dict__, default=lambda x: x.__dict__, ensure_ascii=False)
如果真的要我一层一层手动遍历,那真的就是太惨了。于是一步一步调试,尝试找到原因。
问题原因
经过一番幸苦查找,终于定位到原因,其实很低级的错误。在嵌套class的时候,我有一个地方声明对象实例时,漏掉了()
# 错误写法
column_item = item_class.ClickhouseColumnEntity
# 正确写法
column_item = item_class.ClickhouseColumnEntity()
python中,这两种写法都有,不带()
的写法,直接访问的是对象,而非对象实例,因此我最终组成的列
的列表中,所有的对象都是同一个,且均为最后更新的那个。并且,class对象是不能被json格式化的,故报了以上的异常。
带()
的写法是创建一个对象实例,和Java的用法一样,这也就比较好理解。对象实例列表是可以被json格式化的。
问题发散
在将class对象格式化为json对象的时候,还发现一些其他问题,供参考:
- 通过如下方法设置的默认值,以实例的方式可以访问到,但格式化的时候,不会展现该值,除非重新对属性进行赋值
class A:
attr1 = 'attr1'
attr2: str = 'attr2'
attr3: int
a_instance = A()
a_instance.attr3 = 5
print(json.dumps(a_instance.__dict__)
# 输出结果如下:
# {"attr3":5}
# 对默认值重新赋值
a_instance.attr1 = 'new_attr1'
print(json.dumps(a_instance.__dict__)
# 输出结果如下:
# {"attr3":5, "attr1":"new_attr1"}
如果想让默认值也出现在格式化的字符串中,使用如下方式设置默认值:
class A:
def __init__(self, attr1, attr2='default value', attr3=3):
self.attr1 = attr1
self.attr2 = attr2
self.attr3 = attr3
a_instance = A('attr1', attr3=5)
print(json.dumps(a_instance.__dict__)
# 输出结果如下:
# { "attr1":"attr1", "attr2":"default value", "attr3":5}