2013-12-11 4 views
2

Я надоело писать (2.7) код Python, как это:с-утверждением, что может пропустить свой блок

if "george" in cats and cats["george"] is not None: 
    special_cat = cats["george"] 
    # do something with special_cat 

Так что я написал генератор, который возвращает либо ноль или один объект:

def maybe_get(d, k): 
    if k in d and d[k] is not None: 
     yield d[k] 
    else: 
     return 

Теперь я могу сделать более оригинальный фрагмент кода более компактной, например, так:

for special_cat in maybe_get(cats, "george"): 
    # do something with special_cat 

Использование для цикла для этой цели Лоо ks нечетно. Я бы предпочел использовать контекстный менеджер:

with maybe_get(cats, "george") as special_cat: 
    # do something with special_cat 

Но я не могу понять, какой-либо способ сделать менеджер контекста пропустить блок кода он управляет. (Декодер @contextmanager, например, поднимет RuntimeError, если генератор не даст хотя бы одного значения.) Есть ли трюк, который мне не хватает?

+1

Почему бы не использовать 'if cats.get ('george') не None:' вместо этого? –

+0

Если я это сделаю, мне еще нужна другая строка, чтобы назначить 'special_cat = cats [" george "]'. –

+0

Да, и явный лучше, чем неявный. См. Мой ответ ниже, где вы обращаетесь к словарю только один раз, затем тестируете отдельно. –

ответ

3

Вы не можете использовать диспетчер контекста для «пропуска» блоков кода, для чего это условно. Все, что может сделать менеджер контекста, это подключить к блоку вход и выход, а не управлять, если блок введен в первую очередь.

Я хотел бы использовать:

special_cat = cats.get("george") 
if special_cat is not None: 
    # do something with special_cat 

Это имеет преимущество в том, читаемый и простой. Любые махинации с генераторами или менеджерами контекста увеличили бы удивление для новых разработчиков вашего кода. И помните: вы являетесь новым сопровождающим через год или два от кодовой базы.