问题描述
我在使用 PyYaml 加载/转储需要与 Python 2 和 Python 3 兼容的 yaml 文件时遇到问题。
对于 Python 3 dumping/Python 2 loading,我找到了一个解决方案:
import yaml
data = {"d": "?"}
with open(file_path,"w") as f:
yaml.dump(data,f,allow_unicode=True)
d: ?
如果我尝试使用 Python 2 加载此文件:
with open(file_path,"r") as f:
y = yaml.safe_load(f)
print(y["d"])
我得到以下输出:
?
但是现在如果我尝试使用 Python 2 转储文件,我尝试了:
data = {"d": u"?"}
with open(file_name,"w") as f:
yaml.dump(f)
d: "\uD83D\uDE0B"
我也试过:
data = {"d": u"?".encode("utf-8")}
with open(file_name,"w") as f:
yaml.dump(f)
d: !!python/str "\uD83D\uDE0B"
在这两种情况下,如果我使用 Python 3 加载:
with open(file_path,"r") as f:
y = yaml.load(f)
那么 y["d"]
就是 '\ud83d\ude0b'
不能按原样使用。
我发现我可以做类似的事情
y["d"].encode("utf-16","surrogatepass").decode("utf-16")
但这似乎有点矫枉过正。
那么,使用 Python 2 转储一个在 Python 3 中可读且正确解释的文件的解决方案是什么?
解决方法
我最终为此添加了一个构造函数。
我将它添加到自定义加载器,所以我做了 self.add_constructor
,但它在 yaml 级别是相同的,更容易用它来说明。
yaml.add_constructor("tag:yaml.org,2002:python/str",unicode_constructor)
def unicode_constructor(loader,node):
scalar = loader.construct_scalar(node)
return scalar.encode("utf-16","surrogatepass").decode("utf-16")
这适用于 Python2 转储/Python 3 加载
并且不影响 Python 3 转储/Python 2 或 3 加载