Pythoni c метод для обработки None и с помощью Statement - PullRequest
3 голосов
/ 29 апреля 2020

Я хочу вызвать функцию и передать File -подобный объект или None. Но, используя File -подобный объект, я хочу правильно обработать распределение ресурсов с помощью оператора with. Но Python вызовет исключение (AttributeError), если мое выражение with оценивается как None. Я полагаю, что мог бы написать полный блок try / except от руки, но существует ли лаконичный Pythoni c способ решения этой ситуации?

def call_method(o1, o2, f_in):
    if f_in:
        pass # Do something optional if we have the f_in value

# ...

with (open(path, 'rb') if flag else None) as f_in:
    call_method(opt1, opt2, f_in)
    # Throws an AttributeError, since None does not have __exit__

Ответы [ 4 ]

2 голосов
/ 29 апреля 2020

Если вам нужен контекстный менеджер, который ничего не делает, то это contextlib.nullcontext(), а не None:

import contextlib

with (open(whatever) if flag else contextlib.nullcontext()) as f:
    do_whatever()

f будет None в not flag case - то, что присваивается f, является возвращаемым значением __enter__, которое не обязательно должно быть самим менеджером контекста.

0 голосов
/ 29 апреля 2020

Для Python <3.7 я выполнил это с помощью выражения <code>lambda:

def call_method(o1, o2, get_file):
    if get_file:
        with (get_file() as f_in):
            pass # Do something optional if we have the f_in value

# ...

get_file = (lambda: open(path, 'rb')) if flag else None
call_method(opt1, opt2, get_file)
0 голосов
/ 29 апреля 2020

В том-то и дело, что вы не можете передать None в with, поскольку __exit__ вызывается, когда with закончен. Вместо этого измените это на:

def call_method(o1, o2, f_in):
    # If nothing special is done with None (just a pass) then you don't
    # even need to call this with None, otherwise, you can check f_in like:
    if f_in is None:
        pass
    else:
        pass

if flag:
    with open(path, 'rb') as f_in:
        call_method(opt1, opt2, f_in)
else:
    # only really needed if call_method does something if None is passed
    call_method(opt1, opt2, None)

Другой вариант - использовать nullcontext() вместо None, как указано в другом ответе

0 голосов
/ 29 апреля 2020

Способ сделать это - использовать try / кроме:

try:
    with open(path) as f:
        ...
except OSError:
    pass

Приведенный выше код - если вы намереваетесь что-то сделать с файлом / изменить его, чтобы избежать состояния гонки.

...