Pull to refresh

Прочие варианты использования оператора else

Reading time 3 min
Views 25K
Original author: Amir Rachum
Всем нам хорошо известен способ использования ключевого слова else совместно с if:

if x > 0: 
    print 'positive' 
elif x < 0: 
    print 'negative' 
else: 
    print 'zero' 


Однако в Python’е существует и несколько других, неизвестных большинству программистов, применений else.


for… else


Бьюсь об заклад, что вам неизвестно, что else можно ставить сразу после окончания цикла for! Для чего, спросите вы? Когда элементы перебираемой последовательности будут исчерпаны, управление перейдет коду, находящемуся в блоке else. «А когда эти элементы не будут исчерпаны?» — когда вы выйдете из цикла досрочно по условию break.

Использование else в данном случае может выглядеть неразумным, так как else не совсем верно описывает характер происходящего, однако этот синтаксический сахар может быть полезным тогда, когда у вас в цикле имеется оператор break, и вам необходимо знать, переходило ли к нему управление. Допустим, у нас есть компьютер и список людей, и мы хотим, чтобы каждый из них воспользовался компьютером (до тех пор, пока один из них его не сломает). В конце цикла мы хотим узнать, был ли наш компьютер сломан. Обычно, мы записываем это таким образом:

broken = False 
for person in people: 
    person.use(computer) 
    if computer.is_broken: 
        broken = True 
        break 
if not broken: 
    print 'The computer is fine!' 


С использованием for..else мы можем привести этот код к более удобочитаемой форме:

for person in people: 
    person.use(computer) 
    if computer.is_broken: 
        break 
else: 
    print 'The computer is fine!' 


while… else


Семантика здесь абсолютно та же, что и в предыдущем случае. Тело цикла while выполняется до тех пор, пока верно некое условие — это вы и так уже знаете. Если в какой-то момент условие перестало быть верным, выполнение переходит в ветвь else. Оператор break, если условие дойдет до него, прервет выполнение всего цикла while..else, таким образом, ветвь else выполняться не будет. В двух словах: логика поведения while..else точно такая же, как и у for..else.

while usage < 10 and person.want_to_play: 
    person.use(computer) 
    if computer.broken: 
        break 
else: 
    print 'The computer is fine!' 


try… except… else


Есть некоторый код, заключенный в блоке try. Вы хотите перехватывать определенные исключения, и обрабатывать их, но что, если в процессе выполнения никаких исключений выброшено не было? На помощь приходит условие else. Оно будет выполняться лишь в том случае, когда никаких исключения выброшено не было, и перед блоком finally (если он, конечно, существует). Нужно заметить, что исключения, порожденные в блоке else предшествующими конструкциями except, обрабатываться не будут:

 def get_person(people):
     try:
         person = people[3]
     except IndexError:
         person = None
     else:
         person.do_work()
     return person 


Управление дойдет до ветви else, если иключение IndexError не было выброшено. Почему это может быть полезным? Мы можем внести person.do_work() в блок try, но что произойдет, если do_work() в процессе работы выбросит исключение IndexError? В таком случае, оно будет поймано нашим блоком except, результаты чего могут быть катастрофическими (если конечно мы не приготовились к этому заранее — в таком случае, IndexError, порожденный do_work(), будет проброшен далее, как и происходит в нашей функции get_person(person)).

Заключение


Честно говоря, я не нашел особой пользы от применения оператора else вне связки с if. Я считаю, что в большинстве случаев не следует использовать его вместе с операторами циклов, так как получающиеся конструкции являются не интуитивными (хотя им можно дать “зеленый свет” в ситуациях, когда это приводит к более краткому и удобочитаемому коду). С другой стороны, использование else совместно с try куда как более интуитивно, и, возможно, представляет собой лучшую альтернативу отлавливанию тех исключений, которые нужно пробросить дальше, или использованию флаговой переменной, позволяющей понять, было ли выброшено исключение в процессе работы блока try..except.
Tags:
Hubs:
+70
Comments 52
Comments Comments 52

Articles