Pull to refresh

Comments 63

Спасибо. Продолжайте — у вас хорошо получается.
UFO just landed and posted this here
Поддерживаю. Если официальный сайт технологии выкладывает официальный Programming Stryle Guide, то это правило хорошего тона и профессионализм — использовать эти рекомендации. При обучении, тоже лучше сразу приучать писать согласно этим правилам.
Большое спасибо Вам, а также всем тем кто поддерживает эту тему. Задумался над тем, чтоды добавить изучение Питона для школьников в кружке. Как один из 2-х языков. Первый разумеется Паскаль.
Надо же!!! Это радостное известие для меня. Желаю удачи! :)
> Существует так же краткая форма записи (аналог тернарного оператора в Си): X = A if условие else B

Можно еще упомянуть про логические операторы or и and, которые так же можно использовать для данной конструкции:

x = условие and a or b


Отсюда можно выводить и следующие производные:

b = a or 10 # либо «а», либо дефолтное значение

# можно, например, и функцию вызвать по условию:


def c(): print('O.k')

b and c() # функция «с» вызовется только в том случае, если b — истинно


Все дело в особенности операторов or и and:

— or возвращает левый операнд, если он истинен, иначе — правый;
— and — вернет результат самого правого операнда, если все предыдущие были истины.

Когда условия одиночны, то такая запись может быть очень удобной (не нужно городить лишние if-else-блоки), если же условий несколько, то лучше воспользоваться if-else'ами, чтобы не портить читаемость кода.

P.S.> в JavaScript и Ruby аналогичная функциональность этих операндов.
UFO just landed and posted this here
if условие1:
блок1
elif условие2:
блок2
else:
блок3

elif или elseif?
elif

P.S> в Ruby еще «интересней» — elsif =)
ок, сенькс, буду знать. Непривычно просто=)
большое спасибо… учу с вами питон… продолжайте
товарищ cleg — найдите пожалуйста время и продолжайте уроки, лично я очень жду ;)
Ненужное дублирование:
for elem in list1:
print (elem,'found') if elem in list2 else (elem,'not found')

--->

print (elem,'found' if elem in list2 else 'not found')
Или даже так:

list1 = [1, 2, 3]
list2 = [2]
for elem in list1:
    print(elem, ['not found', 'found'][elem in list2])
Объясните смысл else и finally в try.

Разве это:
try:
..block 1
else:
..block 2
finally:
..block 3


не равнозначно записи
try:
..block 1
..block 2
block 3
У меня поверхностное знакомство с питоном, но могу рискнуть:

В первом случае при возникновении исключения в «block 1», он на самом деле не будет выполнен, т.к. там есть ошибка вызывающая эксепшн, управление перейдёт на «block 2», который выполнится. Затем выполнится «block 3».

Во втором случае, при возникновении эксепшна в «block 1», управление перейдёт сразу на «block 3» минуя «block 2».
UFO just landed and posted this here
UFO just landed and posted this here
Не просто не имеет, но и грамматика это явно запрещает.
Это не так важно, я просто опустил для простоты.
А вот ниже с except. Покомментируете?
try:
    print "TRY!"
finally:
    print "Finally!"

===
TRY!
Finally!

Замечательно работает. Остальное же — да, запрещено, да и смысла, вроде, не имеет. Зачем может понадобиться try/else сочетание — ума не приложу %)
А это уже отдельный вопрос :) Я всё жду, когда начнётся обсуждение исключений, чтобы там позадавать вопросы относительно соответствия реализации языка его формальной грамматике. Грамматика явно требует наличия как минимум одного блока except.

Насчёт try и else

try:
    do_something
except E1:
    # ловим исключение 1
except E2:
    # ловим исключение 2
else:
    # ловим все остальные исключения
finally:
    # делаем что-то там в случае чего-то там


То есть смысл в том, чтобы отловить любое исключение, которое вылезет (считаем, что самого базового класса нет). В такой интерпретации я не вижу особого смысла в блоке finally.
> else: # ловим все остальные исключения
> То есть смысл в том, чтобы отловить любое исключение, которое вылезет (считаем, что самого базового класса нет)

Ветвь else выполнится только в том случае, если блок try не сгенерировал исключение. Рациональное объяснение: лучше дополнительный код, который должен быть выполнен при успешном try'e помещать в else, это позволит избежать обработку исключений, сгенерированных кодом, который мы не собирались защищать.
Да, что-то я совсем фигни нагнал.
Приношу извенения, ошибся. Случай try:… finally в грамматике отдельно рассматривается.
Не так важно, я упростил.

Разве это:
try:
..block 1
except:
..show msg
else:
..block 2
finally:
..block 3

не равнозначно записи
try:
..block 1
..block 2

block 3
Оно само отправляется!
Не так важно, я упростил.

Разве это:
try:
..block 1
except:
..show msg
else:
..block 2
finally:
..block 3

не равнозначно записи
try:
..block 1
..block 2

block 3
И этот вариант сам отправился. Смотрите ниже, пожалуйста.
Разве это:
try:
..block 1
except:
..show msg
else:
..block 2
finally:
..block 3

не равнозначно записи
try:
..block 1
..block 2
except:
..show msg
block 3

За исключением разве обработки исключения в блоке 2.
Я не вижу разницы.
И если уж обработка исключения в блоке 2 принципиальна, разницы в finally нету совсем:

try:
..block A
except:
..show msg
finally:
..block B

эквивалентно

try:
..block A
except:
..show msg
block B
Исключения — это вообще тема для отдельного разговора. Например, в блоке finally нельзя делать continue (в python 2.5 по крайней мере).

Далее пример (finally выполняется всегда):

def f():
    global x
    try:
        x=1
        return
    finally:
        x=3
f()
print x
Позволю себе не согласиться ;)

finally мне видится полезным при работе с ресурсами, которые обязательно надо освободить. В случае же exception-а ресурс может оказаться занятым. Например, открытый файл, сокет, всякие семафоры с флагами и т.п.

Мне сейчас скажут, что есть же with, но он далеко не всегда доступен :( Говорят, в python 3000 with должен поддерживаться большей частью библиотек, для версий же 2.5-2.6 это не так. Сам, недавно испольpуя urllib, с огорчением для себя обнаружил, что с ним with не работает.
Согласен, я выше привёл пример применения finally. Я говорил про некоторые случаи.
в принципе — логика простая.
в блоке
try:
    # blah balh blah
except Error as err:
    # poom poom poom
else:
    # dah dah dah
finally:
    # zoom zoom zoom


блок else выполняется только в том случае если в блоке try не было исключительной ситуации.
а finally — выполнится всегда гарантированно, даже если в блоке try был вызван выход из функции (например)

def func1():
    try:
    #    print 1/0
        pass
        return
    except Exception as ex:
        print repr(ex)
    else:
        print "else"
    finally:
        print "finally"

func1()


попробуйте раскомментировать строчку с делением на ноль, и т.п.
в принципе водогнку…
для try… except… else… finally… usecase весьма прост:

try:
    # делаем что-то критичное
    # можем даже вызвать если надо return
    # обычно - открываем файл, коннектимся к бд и т.п.
except Error as err:
    # ой, словили эксепшн - сообщаем пользователю и т.п.
else:
    # все хорошо, работаем с ресурсом
finally:
    # убираем за собой, и не важно что случится - мы всегда уберем
</code>
Это понятно.
Но ваш код и мой код напишут то же самое:

МЛЯТЬ, почему он отправляется сам??
habrahabr.ru/blogs/starting_programming/50120/#comment_1315751

Блок else идеологически выделен, чтобы вынести в него код, который должен быть выполнен в случае успеха (в случае, если в try не произойдут исключений). Теоретически и практически, весь код блока else можно и записать в сам try, однако, в try желательно писать только то, что должно быть защищено. Остальной успешный код лучше вынести в else, поскольку в самом этом коде могут быть также исключения и, если они будут в try'e, то будут обрабатываться нашими except'aми, которые предназначены для обработки для конкретных типов исключений.
Спасибо, это весьма доходчиво!
Все равно не понятно ЗАЧЕМ это нужно.
Если мы не предусмотрели except для исключения из «успешного» кода, он не будет обработан.
Может кто-нибудь пример из рабочего кода приведет, где это действительно надо делать через else?
> Все равно не понятно ЗАЧЕМ это нужно.

a = {'x': 0}
try:
    b = a['x']
    #b = a['c']
    #print(1 / b)
except KeyError as e:
    print('KeyError')
except Exception as e:
    print('Common Exception')
else:
    print(1 / b)
finally:
    print('finally')

В данном случае, программа упадет на else (поскольку будет деление на 0).

Если в try'e использовать только вторую строку (b = a['c']), то поймается KeyError и else не будет обработан.

Если в try'e использовать строки 1 и 3 (b = a['x'] и print(1 / b)), то поймается общий Exception, но! — не для того случая, который мы защищали (b = a['несуществующий_ключ']), а для «непредвиденного» — из «успешного» кода (в данном случае — тривиальный — деление на ноль, где ноль — предварительно полученный код из защищаемого кода). В данном случае, наш Exception поймал исключение, но предназначался этот Exception не для этого исключения. Т.е. мы будем считать, что мы что-то обработали, на самом же деле — код должен упасть в else, сигнализируя, что помимо кода, который мы защитили, есть еще один такой код и его так же надо обрабатывать, но, возможно, совершенно другими классами исключений (это основная суть).

Так что здесь вопрос, скорее, идеологический (ничто не мешает использовать этот «успешный» код и в самом try'e и вообще — за пределами try-блока), просто ввели такой синтаксический сахар в виде else.

P.S> в Ruby этот else-блок тоже присуствует в данном блоке.
То есть мы просто не хотим ловить деление на 0 в данном месте?
Тогда зачем нам ловить общий Exception?

Ну в общем ясно: хотите — используйте else, хотите — без него.

А если в else будет эксепшн, finally отработает?
> То есть мы просто не хотим ловить деление на 0 в данном месте?

Не ловить в смысле в общих except'ax или сделать еще внутренний try-except в основмном try'e? Первый случай, как раз-таки нежелателен — получается мы общими except'ами пытаемся отловить все, соответственно, и в try'e у нас каша — сколько случаев мы в нем пытаемся защитить?

Если будет внутренний try-except во внешнем try — да, так, конечно, можно, тогда не должно быть внешнего else-блока (поскольку он тоже выполнится, т.к. во внешнем try'e все пройдет успешно).

Однако, если вынести успешный код в else и сделать там try-except — мы разграничиваем типы исключений.

В общем, повторю, это лишь удобный синтаксический сахар (ничто не запрещает написать этот успешный код со своими try-except'aми и после основного try'я)

> А если в else будет эксепшн, finally отработает?

Да.
Нет, подождите. Опять все запутывается. =)
Мы хотим поймать деление на 0 в этом блоке кода?
Если да — то вместо «except Exception as e:» пишем «except ZeroDivisionError as e:».
Если нет — то вместо «except Exception as e:» вообще ничего не пишем.
И не надо никаких вложенных try..except и естественно else.

Единственно возможным вариантом (и то с натяжкой) использования else я вижу ситуацию, когда у нас есть внутри try 2 куска кода, которые могут выбросить одинаковый эксепшн, но первый мы хотим ловить, а второй нет. Или второй мы хотим обработать по другому, и тогда внутри else еще один try..except. Хотя его с тем же успехом можно всунуть внутрь первого try.

> Единственно возможным вариантом (и то с натяжкой)

Для этого и создан этот синтаксический сахар. Без натяжек.
Я бы заменил фразу «# выполнится, если выход из цикла не осуществлялся инструкцией break» на «# выполняется, если выход из цикла был произведён не инструкцией break» для единообразия.
да, статья про расширенное использование функций — будет… надеюсь завтра.
Классная статья, отдельное спасибо за пример.
Хочу добавить пару слов о конструкциях вида: X = A if S else B. Есть еще более экзотичные способы, например:
X = [B, A][bool(S)]
или
X = ( (A and S) or B )
Все 3 примера сработают одинаково.
Не совсем так. Третий пример не эквивалентен первому. Например, когда S имеет ложное значение.
Пример:

>>> A = 0
>>> S = 1
>>> B = 'hi'
>>> A if S else B
0
>>> ((A and S) or B)
'hi'


Второй пример будет работать медленнее, чем первый. Т.к. в первом используется сокращённая схема вычислений, а во втором полная.

Короче говоря, иметь представление об альтернативных вариантах — полезно. Т.к. они могут встретиться в старом коде (когда тернарный оператор ещё не был введён). Но в новом коде следует использовать только первый вариант. Читаемость кода — это тоже немаловажный фактор, согласитесь ;)
> ((A and S) or B)

только наоборот — S and A or B (если сравнивать с A if S else B), но сути это не меняет:

поскольку, действительно, эти два варианта работают по-разному: второй вариант трактует полученный ноль (S and A) как ложь и, соответственно, переходит к вычислению в B. Поэтому, если нужно учитывать 0, второй вариант уже не подходит. Поэтому, да — для общего случая лучше использовать вариант с A if S else B.

Для одиночных же проверок (a and b, c = x || 'defaultValue'), будут работать нормально.
Условная инструкция if
Думаю тут всё понятно:
    if условие1:
        блок1
    elif условие2:
        блок2
    else:
        блок3


Может я где-то что-то упустил, но не могу ни в одной «унции» найти а как, собственно, задается блок, если там больше одного выражения? В примерах не вижу ни привычных {...}, ни какого-нибудь end (хоть c begin как в паскале, хоть без, как в альтернативном синтаксисе PHP)… Глазами смотришь — вроде понятно, что и как должно выполняться, но транслятор же глаз не имеет :)
все дело в волшебных отступах ;)
Понятно, что ничего не понятно :)
Верно. В Унциях про это ни слова. Ввиду очевидности. Роль привычных {} в питоне играют отступы от левого края.
Оригинальный подход и я бы не сказал, что он очевиден, точнее очи видят, а мозг этого не осознает. И сразу же вопросы возникают — за сколько пробелов считается таб, например. Если в других языках это вопрос эстетический и юзабельный, то тут, видимо, принципиальный
Блок можно отделять отступом хоть в один пробел, хоть в десять. Есть лишь рекомендация по использованию четырёх пробелов. Её и советую придерживаться.
Спасибо, будем экспериментировать, а то не очень понятно как транслятор поймет то один пробел, то десять
В данном случае оператор in сам осуществляет обход списка и поиск элемента. Этот вариант решения будет работать быстрее, чем первый.

Почему оператор in работает быстрее?
Sign up to leave a comment.

Articles