Почему я могу использовать одну и ту же функцию для чтения данных YAML из строки и обработчика файла? - PullRequest
0 голосов
/ 11 октября 2019

Мне пришлось читать данные YAML один раз из файла, а другой - из строки. К моему удивлению, оба используют одну и ту же функцию:

import yaml

data = """
hello:
    world
"""
# read the string
doc = yaml.safe_load(data)
print(doc)

# write the string to a file and read the file
with open("data.yaml", 'w') as f:
    f.write(data)
with open("data.yaml", 'r') as f:
    doc = yaml.safe_load(f)
print(doc)

# output:
# {'hello': 'world'}
# {'hello': 'world'}

Почему это так? В первом случае тип данных, передаваемых на yaml.safe_load(), равен str, а в другом случае TextIOWrapper - но оба они одинаково приняты.

Они настолько похожи, что оба могут быть пользовательскими бездискриминация по функции? Или yaml.safe_load() внутренне проверяет, какой тип данных он получает, и соответственно отправляет обработку?

Ответы [ 2 ]

3 голосов
/ 11 октября 2019

Код для Reader здесь здесь

class Reader(object):
    def __init__(self, stream):
        if isinstance(stream, str):
            self.name = "<unicode string>"
            self.check_printable(stream)
            self.buffer = stream+'\0'
        elif isinstance(stream, bytes):
            self.name = "<byte string>"
            self.raw_buffer = stream
            self.determine_encoding()
        else:
            self.stream = stream
            self.name = getattr(stream, 'name', "<file>")
            self.eof = False
            self.raw_buffer = None
            self.determine_encoding()

Таким образом, он проверяет тип stream и обрабатывает его по-другому.

0 голосов
/ 13 октября 2019

Если вам нужно разобрать YAML 1.2, для чего вам понадобится мой ruamel.yaml. на самом деле вы также можете сдать pathlib.Path, и он будет правильно открыт для вас.

Принимая во внимание, что тест для строки / юникода является явным как в PyYAML (для YAML 1.1), так и в ruamel.yaml (YAML 1.2 и 1.1) с использованием isinstance(). Тест для Path выполняется по-другому, так как модуль pathlib по умолчанию недоступен в Python 2 (хотя вы можете установить pathlib2 и импортировать Path оттуда). Поэтому, если бы вы сделали isinstance(arg, Path), вам нужно было бы перехватить возможное исключение.

Вместо метода ruamel.yaml load(), проверяется, что аргумент не имеет метода .read() и имеет *Метод 1014 *, в этом случае он принимает аргумент Path, открывает его и вызывает сам себя:

def load(self, stream):
    if not hasattr(stream, 'read') and hasattr(stream, 'open'):
        # pathlib.Path() instance
        with stream.open('rb') as fp:
            return self.load(fp)
    # processing of string/unicode/opened_file

Таким образом, нигде в коде pathlib фактически не импортировано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...