pyyaml 并仅对字符串使用引号
Posted
技术标签:
【中文标题】pyyaml 并仅对字符串使用引号【英文标题】:pyyaml and using quotes for strings only 【发布时间】:2016-11-17 02:42:36 【问题描述】:我有以下 YAML 文件:
---
my_vars:
my_env: "dev"
my_count: 3
当我用 PyYAML 读取它并再次转储它时,我得到以下输出:
---
my_vars:
my_env: dev
my_count: 3
有问题的代码:
with open(env_file) as f:
env_dict = yaml.load(f)
print(yaml.dump(env_dict, indent=4, default_flow_style=False, explicit_start=True))
我尝试使用default_style
参数:
with open(env_file) as f:
env_dict = yaml.load(f)
print(yaml.dump(env_dict, indent=4, default_flow_style=False, explicit_start=True, default_style='"'))
但现在我明白了:
---
"my_vars":
"my_env": "dev"
"my_count": !!int "3"
我需要做什么来保持原始格式,不对 YAML 文件中的变量名做出任何假设?
【问题讨论】:
为什么不直接打印文件,重要的是使用字典作为打印内容的来源而不是文件本身吗? 以后我会在字典中添加额外的键,但是布局需要保留。 【参考方案1】:您可以使用以下方法将您的double quoted scalar
对象保留在yaml
中:
以你的 yaml 为例:
---
my_vars:
my_env: "dev"
my_count: 3
将其加载到 env_dict(字典)中:
myyaml = '''
---
my_vars:
my_env: "dev"
my_count: 3
'''
env_dict = yaml.load(myyaml, yaml.FullLoader) # loading yaml
print(env_dict)
'my_vars': 'my_env': 'dev', 'my_count': 3
# Define a quoted class, which uses style = '"' and add representer to yaml
class quoted(str):
pass
def quoted_presenter(dumper, data):
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
yaml.add_representer(quoted, quoted_presenter)
# Now, we update the dictionary env_dict as follows for the "dev"
# value which needs to be a double quoted scalar
env_dict['my_vars'].update(my_env = quoted("dev")) # this makes "dev"
# a double quoted scalar
# Now, we dump the yaml as before
yaml.dump(env_dict, sys.stdout, indent=4, default_flow_style=False, explicit_start=True)
# which outputs
---
my_vars:
my_count: 3
my_env: "dev"
这些链接帮助我得出了这个答案:Any yaml libraries in Python that support dumping of long strings as block literals or folded blocks?
How can I control what scalar form PyYAML uses for my data?
另外,这篇文章很适合在To Quote or not to Quote?阅读
希望,这会有所帮助!
【讨论】:
【参考方案2】:我建议您更新为使用带有向后兼容 ruamel.yaml
包的 YAML 1.2(2009 年发布),而不是使用实现大部分 YAML 1.1 (2005) 的 PyYAML。 (免责声明:我是该软件包的作者)。
然后,您只需在加载往返 YAML 文件时指定 preserve_quotes=True
:
import sys
import ruamel.yaml
yaml_str = """\
---
my_vars:
my_env: "dev" # keep "dev" quoted
my_count: 3
"""
data = ruamel.yaml.round_trip_load(yaml_str, preserve_quotes=True)
ruamel.yaml.round_trip_dump(data, sys.stdout, explicit_start=True)
哪些输出(包括保留的评论):
---
my_vars:
my_env: "dev" # keep "dev" quoted
my_count: 3
在加载字符串后,标量将成为字符串的子类,以便能够容纳引用信息,但对于所有其他用途,它们将像普通字符串一样工作。如果你想替换这样的字符串(dev
到 fgw
)
您必须将字符串转换为该子类(DoubleQuotedScalarString
来自 ruamel.yaml.scalarstring
)。
当往返ruamel.yaml
默认情况下会保留键的顺序(通过插入)。
【讨论】:
【参考方案3】:对,所以从this answer 大量借用,你可以这样做:
import yaml
# define a custom representer for strings
def quoted_presenter(dumper, data):
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
yaml.add_representer(str, quoted_presenter)
env_file = 'input.txt'
with open(env_file) as f:
env_dict = yaml.load(f)
print yaml.dump(env_dict, default_flow_style=False)
但是,这只是在字典中的 all 字符串类型上重载它,因此它也会引用键,而不仅仅是值。
打印出来:
"my_vars":
"my_count": 3
"my_env": "dev"
这是你想要的吗?不知道你说的变量名是什么意思,你是指键吗?
【讨论】:
这对我有很大帮助,谢谢 :-) 仍然不确定如何仅将其应用于值,而不是键。 如果你有很多空闲时间,那么我建议你去 yaml 的 documentation 了解如何创建代表,然后彻底阅读 YAML 的标签 here。还有 this answer 讨论了 PyYaml 的一个分支,它确实提到了一些关于保持原始格式的内容,可能也会有所帮助。以上是关于pyyaml 并仅对字符串使用引号的主要内容,如果未能解决你的问题,请参考以下文章
PyYaml - 使用特殊字符(即重音符号)转储 unicode