假设我有一个天真的类定义:
import yaml
class A:
def __init__(self):
self.abc = 1
self.hidden = 100
self.xyz = 2
def __repr__(self):
return yaml.dump(self)
A()
印刷
!!python/object:__main__.A
abc: 1
hidden: 100
xyz: 2
是否有一种干净的方法可以从yaml dump的打印输出中删除包含hidden: 100
的行?密钥名称hidden
已提前知道,但其数字值可能会更改。
期望的输出:
!!python/object:__main__.A
abc: 1
xyz: 2
仅供参考:此转储仅供显示,不会加载。
我想可以使用hidden
使用key = yaml.representative
来抑制键/值对。另一种方法是在字符串输出中使用RegEx查找hidden: [number]
。
答案 0 :(得分:1)
我查看了pyyaml的文档,但没有找到实现目标的方法。解决方法是删除属性hidden
,调用yaml.dump
,然后将其添加回来:
def __repr__(self):
hidden = self.hidden
del self.hidden
return yaml.dump(self)
self.hidden = hidden
退一步,为什么要将yaml
用于__repr__
?你可以自己动手而不是依靠yaml
吗?
答案 1 :(得分:1)
json
是成熟的解决方案,并且(在撰写本文时)有比pyyaml
更好的文档;
我会使用它,而pyyaml
的文档很难完全理解。作为奖励,YAML(几乎)是JSON的超集,因此您可以在不转换数据的情况下将您的数据读取为YAML。
但是,要轻松使用YAML的所有好东西,您可能需要将数据转换为YAML
json
模块默认情况下无法序列化自定义对象,但可以轻松扩展:
import json
def default(o):
if isinstance(o, A):
result = vars(o).copy()
del result['hidden']
result['__class__'] = o.__class__.__name__
return result
else:
return o
json.dumps(A(), default=default) # => '{"__class__": "A", "xyz": 2, "abc": 1}'
如果您不想在default=default
的任何地方写dumps
,则可以创建自定义序列化程序:
dumper = json.JSONEncoder(default=default)
dumper.encode(A()) # => '{"__class__": "A", "xyz": 2, "abc": 1}'
或者,能够通过子类化进一步轻松扩展它:
class Dumper(json.JSONEncoder):
__slots__ = ()
def default(self, o):
if isinstance(o, A):
result = vars(o).copy()
del result['hidden']
result['__class__'] = o.__class__.__name__
return result
else:
return super().default(o)
dumper = Dumper()
dumper.encode(A()) # => '{"__class__": "A", "xyz": 2, "abc": 1}'
请注意,JSON中的字段是无序的
另外,如果你想使用它,我建议你不要用密钥__class__
序列化dict,因为它可能很难将它与序列化对象区分开来。