【发布时间】:2011-07-25 22:28:09
【问题描述】:
我有这个:
user_dir: /home/user
user_pics: /home/user/pics
如何将user_dir 用于user_pics?如果我必须像这样指定其他属性,它不会很干燥。
【问题讨论】:
标签: concatenation yaml
我有这个:
user_dir: /home/user
user_pics: /home/user/pics
如何将user_dir 用于user_pics?如果我必须像这样指定其他属性,它不会很干燥。
【问题讨论】:
标签: concatenation yaml
你可以使用一个重复的节点,像这样:
user_dir: &user_home /home/user
user_pics: *user_home
我不认为你可以连接,所以这不会工作:
user_dir: &user_home /home/user
user_pics: *user_home/pics
【讨论】:
令人惊讶的是,由于 YAML 锚点和引用的目的是从 YAML 数据文件中排除重复,因此没有使用引用连接字符串的内置方法。您从部件构建路径名的用例就是一个很好的例子——肯定有很多这样的用途。
幸运的是,有一种简单的方法可以通过 Python 中的自定义标签将字符串连接添加到 YAML。
import yaml
## define custom tag handler
def join(loader, node):
seq = loader.construct_sequence(node)
return ''.join([str(i) for i in seq])
## register the tag handler
yaml.add_constructor('!join', join)
## using your sample data
yaml.load("""
user_dir: &DIR /home/user
user_pics: !join [*DIR, /pics]
""")
结果:
{'user_dir': '/home/user', 'user_pics': '/home/user/pics'}
如果字符串需要分隔,您可以向数组中添加更多项,例如 " " 或 "-"。
【讨论】:
yaml 包的源代码。它只是使用其公共 API 以 YAML 规范允许的方式对其进行扩展。
如果您在 PyYaml 中使用 python,则可以在 YAML 文件中连接字符串。不幸的是,这只是一个 python 解决方案,不是通用的:
os.path.join:
user_dir: &home /home/user
user_pics: !!python/object/apply:os.path.join [*home, pics]
使用string.join(为了完整起见 - 此方法可灵活用于多种形式的字符串连接:
user_dir: &home /home/user
user_pics: !!python/object/apply:string.join [[*home, pics], /]
【讨论】:
yaml.safe_load() 函数来避免安全问题。在这种情况下,您的代码将无法工作。
cannot find module 'str' (No module named 'str')
我会使用一个数组,然后将字符串与当前的操作系统分隔符连接在一起
像这样:
default: &default_path "you should not use paths in config"
pictures:
- *default_path
- pics
【讨论】:
在我看来,YAML 本身 does not define way to do this。
好消息是 YAML 使用者或许能够理解变量。
什么将使用您的 YAML?
【讨论】:
string.join() 在 Python3 中不起作用,但您可以像这样定义 !join:
import functools
import yaml
class StringConcatinator(yaml.YAMLObject):
yaml_loader = yaml.SafeLoader
yaml_tag = '!join'
@classmethod
def from_yaml(cls, loader, node):
return functools.reduce(lambda a, b: a.value + b.value, node.value)
c=yaml.safe_load('''
user_dir: &user_dir /home/user
user_pics: !join [*user_dir, /pics]''')
print(c)
【讨论】:
截至 2019 年 8 月:
要使Chris' 解决方案有效,您实际上需要将Loader=yaml.Loader 添加到yaml.load()。最终,代码将如下所示:
import yaml
## define custom tag handler
def join(loader, node):
seq = loader.construct_sequence(node)
return ''.join([str(i) for i in seq])
## register the tag handler
yaml.add_constructor('!join', join)
## using your sample data
yaml.load("""
user_dir: &DIR /home/user
user_pics: !join [*DIR, /pics]
""", Loader=yaml.Loader)
更多讨论请见this GitHub issue。
【讨论】: