PyYAMLでカスタムタグを使う
調べてみたら全くといっていいほどサンプルが(英語圏にも!)なかったので簡単なのを
きっかけ
YAMLでプログラムの挙動を定義するコードをPythonで書いていて、ちょっとYAML内にオブジェクトを生成する処理を書きたくなりました。
PyYAMLDocumentationを見る限りタグというものがあって、どうもそれが目的のことをやってくれそうなのですが、どこにも利用例がなくどう使えばいいのか、どう定義すればいいのかが分かりません。さて困った。
タグを追加する方法
で、いきなり本題です。タグを追加するには、PyYAMLモジュールのグローバル関数、add_multi_constructor()
というものに値を渡せば良い。
yaml.add_multi_constructor("tag:yaml.org,2002:var", var_handler)
# ...
def var_handler(loader, suffix, node=None):
# 処理
こういうコードを書くと、YAMLファイルに以下のようなタグがあったときに反応し、var_handler
が呼び出される。
textvariable: !!var:StringVar
name: label
default: ""
引数に指定した関数には三つのパラメータが引き渡され
- loader:読み込み中のYAMLファイルを処理しているローダーオブジェクトそのもの
- suffix:タグプレフィックスの後ろに続く文字列。上記YAMLコードの場合、
:StringVar
- node:タグを発見した箇所を示すノードオブジェクト。valueにはここより下の下位層にあるノードが格納される。
上記YAMLコードの場合、
MappingNode(value=[(ScalarNode(), ScalarNode()), (ScalarNode(), ScalarNode())])
で、関数の戻り値としてなんらかの値をリターンすると、タグの部分が戻り値に指定した値になる。
たとえば上記例の場合、「Yes」という文字を返すと、textvariable: Yes
と書いたのと同じようになる。
add_multi_constructor()
関数の挙動を追ってみると、キーワード引数として定義されているLoaderを省略した場合、ここで指定した関数はLoader, FullLoader, UnsafeLoaderの三つのクラスに追加されるようです。なので、SafeLoaderを使った場合は、ここで何をしたとしても関数は追加されません。
YAMLで独自に定義したタグだけを使いたい場合
YAMLを読み込むとき、独自で定義したタグのみを読み込みたい場合は、SafeLoaderを引数で指定して関数を追加すると良いです。
わたしは別の処理もあったのと、SafeLoaderを直接いじってしまうことに一抹の不安を感じたため、SafeLoaderを継承した新しいクラスを定義してしまいました。
class GeneratorLoader(yaml.SafeLoader):
def __init__(self, stream):
super().__init__(stream)
yaml.add_multi_constructor("tag:yaml.org,2002:var", GeneratorLoader.var_handler,
Loader=GeneratorLoader)
@staticmethod
def var_handler(loader, suffix, node=None):
pass
ここで作ったクラスをyaml.load()
メソッドでLoaderとして使用すれば、タグが処理されるようになります。
PyYAMLのグローバル関数には、Loaderのインスタンスを受け取る関数がない
なお、yaml.load()
などPyYAMLの__init__.pyに定義されている関数には、Loaderのインスタンスを受け取る関数がありません(すべてクラスを受け取っています)。
このため、上記で作成したLoaderオブジェクトを、YAML読み込み後に使用したい場合は、Loader#get_single_data()
を直接呼び出す必要があります。
loader = GeneratorLoader(self.string)
struct = loader.get_single_data()
その他の注意点
- タグは必ず「tag:yaml.org,2002」ではじまる必要があります。よって
add_multi_constructor()
関数の第一引数の値は必ず「tag:yaml.org,2002」からはじまります。ただし、この部分は実際にYAMLには書きません(「tag:yaml.org,2002:var」というタグを定義した場合、YAMLに書くのは「var」のみとなります)
説明がよくわからないからとりあえずコードを見せろ
現在作りかけですが次のモジュールで使用しています。
2020/09/21現在はtksugar/generator.py
に当該処理があります(あとでコードを移動させるかも)。
参考文献
Author And Source
この問題について(PyYAMLでカスタムタグを使う), 我々は、より多くの情報をここで見つけました https://qiita.com/TakamiChie/items/1666e6399b5e93a9e8f8著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .