Страницы

Поиск по вопросам

вторник, 28 января 2020 г.

Как сделать метод пригодным для with?

#python #python_3x


Есть метод-обертка для загрузки YAML в объект. 

def load_yaml(path):
    with io.open(path, encoding='utf-8') as fp:
        return yaml.safe_load(fp)


Хочу использовать with с этим методом:

with load_yaml('data.yml') as data:
    pass


Получаю ошибку:

    ...
    with load_yaml('data.yml) as data:
AttributeError: __enter__


Что я делаю не так? Какие требования предъявляются к методу, чтобы его можно было
использовать с with?
    


Ответы

Ответ 1



Требования предъявляются не к "методу" (у вас, кстати, это не метод, а обычная функция), а к результату, который возвращает этот "метод". После with вообще может стоять не только вызов функции, но и абсолютно любое выражение - сначала оно будет полностью вычислено, и уже над его результатом будет совершаться with. И вот как раз к этому результату есть определённые требования. Для того, чтобы объект можно было использовать в with, у этого объекта должны быть определены специальные методы __enter__ и __exit__. Именно в этих методах вы и объясняете интерпретатору, как он должен открыть контекст работы с этим объектом и потом безопасно закрыть его. Более подробно вы можете нагуглить по запросу "питон контекстный менеджер" или прочитать здесь: https://habrahabr.ru/post/186608/#context https://habrahabr.ru/post/196382/

Ответ 2



class A: def __init__(self, var: list): self.var = var def __enter__(self): self.var.append('enter') return self.var def __exit__(self, exc_type, exc_val, exc_tb): self.var.clear() with A([1]) as ls: ls.append(2) print(ls) # [1, 'enter', 2] print(ls) # [] или import contextlib @contextlib.contextmanager def func(var: list): try: var.append('enter') yield var finally: var.clear() with func([1]) as ls: ls.append(2) print(ls) # [1, 'enter', 2] print(ls) # []

Комментариев нет:

Отправить комментарий