如何将 yaml.load_all 与 fileinput.input 一起使用?

CJ *_*net 5 python pyyaml

而不诉诸''.join,有没有使用PyYAML的一个Python化的方式yaml.load_allfileinput.input()来自多个源的多个文件容易流?

我正在寻找类似以下的内容(非工作示例):

# example.py
import fileinput

import yaml

for doc in yaml.load_all(fileinput.input()):
    print(doc)
Run Code Online (Sandbox Code Playgroud)

预期输出:

$ cat >pre.yaml <<<'--- prefix-doc'
$ cat >post.yaml <<<'--- postfix-doc'
$ python example.py pre.yaml - post.yaml <<<'--- hello'
prefix-doc
hello
postfix-doc
Run Code Online (Sandbox Code Playgroud)

当然,yaml.load_all需要字符串、字节或类似文件的对象,fileinput.input()而这些都不是,因此上面的示例不起作用。

实际输出:

$ python example.py pre.yaml - post.yaml <<<'--- hello'
...
AttributeError: FileInput instance has no attribute 'read'
Run Code Online (Sandbox Code Playgroud)

您可以使示例与 一起使用''.join,但这是作弊。我正在寻找一种不会一次将整个流读入内存的方法。

我们可以将问题重新表述为是否有某种方法可以模拟字符串、字节或类似文件的对象来代理字符串的底层迭代器?但是,我怀疑这是否yaml.load_all真的需要整个类似文件的界面,因此措辞会要求比严格必要的更多。

理想情况下,我正在寻找支持以下内容的最小适配器:

for doc in yaml.load_all(minimal_adapter(fileinput.input())):
    print(doc)
Run Code Online (Sandbox Code Playgroud)

lar*_*sks 5

问题fileinput.input在于生成的对象没有read方法,这就是yaml.load_all正在寻找的方法。如果你愿意放弃fileinput,你可以编写自己的类来做你想做的事:

import sys                                                                      
import yaml                                                                     

class BunchOFiles (object):                                                     
    def __init__(self, *files):                                                 
        self.files = files                                                      
        self.fditer = self._fditer()                                            
        self.fd = self.fditer.next()                                            

    def _fditer(self):                                                          
        for fn in self.files:                                                   
            with sys.stdin if fn == '-' else open(fn, 'r') as fd:               
                yield fd                                                        

    def read(self, size=-1):                                                    
        while True:                                                             
            data = self.fd.read(size)                                           

            if data:                                                            
                break                                                           
            else:                                                               
                try:                                                            
                    self.fd = self.fditer.next()                                
                except StopIteration:                                           
                    self.fd = None                                              
                    break                                                       

        return data                                                             

bunch = BunchOFiles(*sys.argv[1:])                                              
for doc in yaml.load_all(bunch):                                                
    print doc                                                                   
Run Code Online (Sandbox Code Playgroud)

BunchOFiles类让你的对象具有read将愉快地叠代的文件列表,直到一切都用尽方法。鉴于上面的代码和您的示例输入,我们得到了您正在寻找的输出。