Python 标准标记的PyYAML替代构造函数

Python 标准标记的PyYAML替代构造函数,python,yaml,pyyaml,Python,Yaml,Pyyaml,在尝试创建能够扩展变量的加载程序时,我注意到PyYAML在使用块标量时没有扩展变量(例如-)。那么,就拿这个例子来说: # ademo.yml key1: foo key2: bar $LOL bar key3: >- baz $ASD baz 要展开变量,我执行了以下操作: # yaamer.py import re import sys import yaml # I create a loder class MyLoader(yaml.SafeLoader): pass

在尝试创建能够扩展变量的加载程序时,我注意到PyYAML在使用块标量时没有扩展变量(例如
-
)。那么,就拿这个例子来说:

# ademo.yml
key1: foo
key2: bar $LOL bar
key3: >-
    baz $ASD baz
要展开变量,我执行了以下操作:

# yaamer.py
import re
import sys
import yaml

# I create a loder
class MyLoader(yaml.SafeLoader): pass

# Add to it an implicit resolver that matches variables
matcher = re.compile(r".*\$[A-Z].*")
MyLoader.add_implicit_resolver("!path", matcher, None)

# Add a constructor that would replaces the variable
def cons(loader, node):
    print("Constructing for", node)
    return "FOO"
MyLoader.add_constructor("!path", cons)

with open(sys.argv[1]) as inf:
    print(yaml.load(inf, MyLoader))
当我调用它时,
python yaamer.py ademo.yml
,我得到以下输出:

Constructing for ScalarNode(tag='!path', value='bar $LOL bar')
{'key1': 'foo', 'key2': 'FOO', 'key3': 'baz $ASD baz'}
Matching ('key1',) {}
Matching ('foo',) {}
Matching ('key2',) {}
Matching ('bar $LOL bar',) {}
Matching ('key3',) {}
Constructing for ScalarNode(tag='!path', value='bar $LOL bar')
{'key1': 'foo', 'key2': 'FOO', 'key3': 'baz $ASD baz'}
因此,替换仅在键2中,而不是键3中

为了了解发生了什么,我为regex实现了一个包装器,让我能够了解发生了什么:

class Matcher:
    def __init__(self):
        self.matcher = re.compile(r".*\$[A-Z].*")                                                                 
    def match(self, *args, **kwargs):
        print("Matching", args, kwargs)
        return self.matcher.match(*args, **kwargs)
使用它可以得到以下输出:

Constructing for ScalarNode(tag='!path', value='bar $LOL bar')
{'key1': 'foo', 'key2': 'FOO', 'key3': 'baz $ASD baz'}
Matching ('key1',) {}
Matching ('foo',) {}
Matching ('key2',) {}
Matching ('bar $LOL bar',) {}
Matching ('key3',) {}
Constructing for ScalarNode(tag='!path', value='bar $LOL bar')
{'key1': 'foo', 'key2': 'FOO', 'key3': 'baz $ASD baz'}
匹配中没有块标量的痕迹!因此,显然,这个匹配器从未用于解析
-

所以我调查发现有一些,比如
!!str
!!地图
。我认为,由于
>-
是一种特殊的语法,它会自动与其中一个标记匹配

因此,我继续为所有标记安装自定义构造函数,以查看是否调用了其中任何一个:

def make_cons(name):
    def _cons(loader, node):
        print("Constructor for", name)
        return node.value
    return _cons

MyLoader.add_constructor("!!str", make_cons('!!str'))
MyLoader.add_constructor("!!int", make_cons('!!int'))

但是他们从来没有被召唤过!发生了什么事??如果我必须为预先存在的YAML标记安装自定义构造函数,我该怎么做???

隐式解析器只能匹配普通标量,而不能引用。引号表示单引号或双引号,或文字或折叠块标量。因此,您的
key3
是一个折叠块标量,因此不考虑进行匹配

您可以显式添加
!path
在YAML源代码中标记它,然后将调用自定义构造函数

请参阅,并查找单词“隐式”和“普通”

要为标准标记添加构造函数,需要使用全名<代码>!!str只是标签:yaml.org,2002:str的简写:

yaml.add_constructor('tag:yaml.org,2002:str', my_constructor)

非常感谢。所以,如果
!!str是一种速记,但不能在那里使用。。。它是否仅限于文档?或者它在API中有作用?它是一种速记,可以在YAML文档中使用。也许是我妈妈解释的。YAML处理器在解析时将其转换为长版本。您可以通过
%TAG
指令定义自己的速记,但是
是默认值