【发布时间】:2016-01-09 00:38:57
【问题描述】:
我刚刚开始使用 YAML(通过 pyyaml),我想知道是否有任何方法可以声明键的值是键名本身或父键。 例如
---
foo: &FOO
bar: !.
baz: !..
foo2:
<<: *FOO
…
{‘foo’: {‘bar’: ‘bar’, ‘baz’: ’foo’}, ‘foo2’:{‘bar’:’bar’, ‘baz’:’foo2’}}
(请注意 bar 和 baz 上的点和双点 - 它们只是用于获取键名和父键名的占位符)
我试过使用add_constructor:
def key_construct(loader, node):
# return the key here
pass
yaml.add_constructor('!.', key_construct)
但是 Node,不持有密钥(或对父级的引用),我找不到获取它们的方法。
编辑:
所以,这是我的真实用例和基于 Anthon 回复的解决方案: 我有一个记录器配置文件(在 yaml 中),我想在那里重用一些定义:
handlers:
base: &base_handler
(): globals.TimedRotatingFileHandlerFactory
name: ../
when: midnight
backupCount: 14
level: DEBUG
formatter: generic
syslog:
class: logging.handlers.SysLogHandler
address: ['localhost', 514]
facility: local5
level: NOTSET
formatter: syslog
access:
<<: *base_handler
error:
<<: *base_handler
loggers:
base: &base_logger
handlers: [../, syslog]
qualname: ../
access:
<<: *base_logger
error:
<<: *base_logger
handlers: [../, syslog, email]
Anthon 建议的解决方案是在处理完配置字典后遍历配置字典:
def expand_yaml(val, parent=None, key=None, key1=None, key2=None):
if isinstance(val, str):
if val == './':
parent[key] = key1
elif val == '../':
parent[key] = key2
elif isinstance(val, dict):
for k, v in val.items():
expand_yaml(v, val, k, k, key1)
elif isinstance(val, list):
parent[key] = val[:] # support inheritance of the list (as in *base_logger)
for index, e in enumerate(parent[key]):
expand_yaml(e, parent[key], index, key1, key2)
return val
【问题讨论】:
-
这可能是一个剪切和粘贴错误,但 Unicode 字符 2026,如您的源代码中一样,会给您一个 ScannerError。您可能指的是
...而不是…。但一般来说,这些文档开始和结束标记对于单个文档文件不是必需的。 -
感谢@Anthon,我实际上并没有使用它们。为了清楚起见,我添加了它们(以区分代码和结果)