Для чого передбачається використання необов'язкового elseпункту tryтвердження?
Для чого передбачається використання необов'язкового elseпункту tryтвердження?
Відповіді:
Виписки в elseблоці виконуються, якщо виконання випадає з нижньої частини поля try- якщо не було винятком. Чесно кажучи, я ніколи не знаходив потреби.
Однак обробка виключень зазначає:
Використовувати інший пункт краще, ніж додавати додатковий код до пункту спробу, тому що це дозволяє уникнути випадкового лову винятку, який не був піднятий захищеним кодом спробу ... крім оператора.
Отже, якщо у вас є метод, який може, наприклад, кинути an IOError, і ви хочете вилучити винятки, які він збільшує, але ви хочете зробити щось інше, якщо перша операція буде успішною, і ви не хочете зловити IOError від цю операцію, ви можете написати щось подібне:
try:
operation_that_can_throw_ioerror()
except IOError:
handle_the_exception_somehow()
else:
# we don't want to catch the IOError if it's raised
another_operation_that_can_throw_ioerror()
finally:
something_we_always_need_to_do()
Якщо ви просто поставите another_operation_that_can_throw_ioerror()після цього operation_that_can_throw_ioerror, exceptвикличе помилки другого дзвінка. І якщо ви поставите його після цілого tryблоку, він завжди буде запущений, і не після цього finally. elseДозволяє переконатися ,
finallyблоком, іIOErrorякі вирощування тут не спійманіreturn, continueабо break.
Є одна велика причина використання else- стиль та читабельність. Як правило, добре зберігати код, який може спричинити винятки біля коду, який ними займається. Наприклад, порівняйте:
try:
from EasyDialogs import AskPassword
# 20 other lines
getpass = AskPassword
except ImportError:
getpass = default_getpass
і
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
else:
# 20 other lines
getpass = AskPassword
Другий з них хороший, коли exceptне може повернутися рано чи повторно викинути виняток. Якщо можливо, я б написав:
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
return False # or throw Exception('something more descriptive')
# 20 other lines
getpass = AskPassword
Примітка. Відповідь скопійована з нещодавно опублікованого тут дубліката , звідси і все це "AskPassword".
Одне використання: перевірити деякий код, який повинен створити виняток.
try:
this_should_raise_TypeError()
except TypeError:
pass
except:
assert False, "Raised the wrong exception type"
else:
assert False, "Didn't raise any exception"
(Цей код повинен бути абстрагований на більш загальному тесті на практиці.)
Python try-else
Для чого передбачається використання необов'язкового
elseзастереження спробувати test?
Передбачуване використання має мати контекст для запуску більшої кількості коду, якщо не було винятків, коли це очікувалося для обробки.
Цей контекст дозволяє уникнути випадкових помилок, яких ви не очікували.
Але важливо зрозуміти точні умови , які викликають ще пункт про перспективу, тому що return, continueі breakможе перервати потік управління в else.
elseЗаява працює , якщо немає жодного винятку , і якщо не переривається return, continueабо breakзаяву.
Додатковий
elseпункт виконується , якщо і коли управління відтікає в кінці цьогоtryпункту. *
(Сміливий додав.) А виноска йде:
* В даний час, управління «відтікає кінця» , за винятком того, в разі виключення або виконання
return,continueабоbreakзаяви.
Для цього потрібен принаймні один попередній, крім пункту ( див. Граматику ). Тож насправді це не "пробувати інше", це "пробувати, окрім іншого ((остаточно)", при цьому else(і finally) є необов'язковим.
В Python Tutorial конкретизує передбачуваного використання:
Оператор try ... крім вибору має необов'язкове інше застереження, яке, за наявності, повинно дотримуватися всіх, крім пунктів. Це корисно для коду, який повинен бути виконаний, якщо пробний пункт не викликає винятку. Наприклад:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()Використовувати інший пункт краще, ніж додавати додатковий код до пункту спробу, тому що це дозволяє уникнути випадкового лову винятку, який не був піднятий захищеним кодом спробу ... крім оператора.
elseвід коду за tryблокомЯкщо ви обробляєте помилку, elseблок не запускається. Наприклад:
def handle_error():
try:
raise RuntimeError('oops!')
except RuntimeError as error:
print('handled a RuntimeError, no big deal.')
else:
print('if this prints, we had no error!') # won't print!
print('And now we have left the try block!') # will print!
І зараз,
>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!
Спробуйте, крім іншого, відмінно підходить для поєднання схеми EAFP з набором тексту :
try:
cs = x.cleanupSet
except AttributeError:
pass
else:
for v in cs:
v.cleanup()
Ви можете сказати, що цей наївний код добре:
try:
for v in x.cleanupSet:
v.clenaup()
except AttributeError:
pass
Це прекрасний спосіб випадкового приховування серйозних помилок у вашому коді. Я надрукував там очищення, але AttributeError, який дав би мені знати, проковтується. Гірше, що, якби я написав це правильно, але метод очищення періодично передавали тип користувача, який мав неправильний атрибут, внаслідок чого він мовчки провалювався на півдорозі та залишав файл незакритим? Удачі налагодження цього.
Я вважаю це дійсно корисним, коли у вас є очищення, що потрібно зробити, навіть якщо є виняток:
try:
data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
handle_exception(e)
else:
do_stuff(data)
finally:
clean_up()
Незважаючи на те, що ви зараз не можете подумати про його використання, ви можете зробити ставку, що це має бути корисно. Ось непередуманий зразок:
З else:
a = [1,2,3]
try:
something = a[2]
except:
print "out of bounds"
else:
print something
Без else:
try:
something = a[2]
except:
print "out of bounds"
if "something" in locals():
print something
Тут ви somethingвизначили змінну, якщо не буде видано жодної помилки. Ви можете видалити це за межами tryблоку, але тоді воно потребує деякого безладного виявлення, якщо визначена змінна.
something = a[2]; print somethingблоком try: block?
Там хороший приклад try-elseв PEP 380 . В основному, це зводиться до виконання різної обробки виключень у різних частинах алгоритму.
Це щось подібне:
try:
do_init_stuff()
except:
handle_init_suff_execption()
else:
try:
do_middle_stuff()
except:
handle_middle_stuff_exception()
Це дозволяє записати код оброблення виключень ближче до місця, де відбувається виняток.
З помилок та винятків # Обробка виключень - docs.python.org
У
try ... exceptзаяві є необов’язковеelseзастереження, яке, за наявності, повинно відповідати всім, окрім пунктів Це корисно для коду, який повинен бути виконаний, якщо пробний пункт не викликає винятку. Наприклад:for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()Використовувати інший пункт краще, ніж додавати додатковий код до пункту спробу, тому що це дозволяє уникнути випадкового лову винятку, який не був піднятий захищеним кодом спробу ... крім оператора.
Переглядаючи посилання Python, здається, що elseвоно виконується після того, tryяк немає винятку. Необов'язковий інший пункт виконується, якщо і коли управління відтікає від кінця спробу. 2 Винятки з іншого пункту не обробляються попередніми, окрім пунктів.
Занурення в python має приклад, коли, якщо я правильно розумію, у tryблоці вони намагаються імпортувати модуль, коли це не вдається, ви отримуєте виняток і прив'язуєте за замовчуванням, але коли він працює, у вас є можливість перейти до elseблоку та зв’язати те, що потрібно (див. посилання для прикладу та пояснення).
Якщо ви спробували виконати роботу в catchблоці, це може спричинити ще один виняток - я думаю, саме тут цей elseблок стане у нагоді.
tryблоку.
Це воно. Блок 'else' пункту спробу виключення існує для коду, який запускається, коли (і лише тоді), коли випробувана операція успішна. Це можна використовувати, і ним можна зловживати.
try:
fp= open("configuration_file", "rb")
except EnvironmentError:
confdata= '' # it's ok if the file can't be opened
else:
confdata= fp.read()
fp.close()
# your code continues here
# working with (possibly empty) confdata
Особисто мені це подобається і використовую, коли це доречно. Він семантично групує твердження.
Можливо, користь може бути:
#debug = []
def debuglog(text, obj=None):
" Simple little logger. "
try:
debug # does global exist?
except NameError:
pass # if not, don't even bother displaying
except:
print('Unknown cause. Debug debuglog().')
else:
# debug does exist.
# Now test if you want to log this debug message
# from caller "obj"
try:
if obj in debug:
print(text) # stdout
except TypeError:
print('The global "debug" flag should be an iterable.')
except:
print('Unknown cause. Debug debuglog().')
def myfunc():
debuglog('Made it to myfunc()', myfunc)
debug = [myfunc,]
myfunc()
Можливо, це теж призведе до вашої користі.
Я вважаю цю try: ... else:конструкцію корисною в ситуації, коли ви виконуєте запити до бази даних та записуєте результати цих запитів в окрему базу даних того ж аромату / типу. Скажімо, у мене є безліч робочих ниток, всі запити обробки баз даних, подані до черги
#in a long running loop
try:
query = queue.get()
conn = connect_to_db(<main db>)
curs = conn.cursor()
try:
curs.execute("<some query on user input that may fail even if sanitized">)
except DBError:
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of failed query")
logcurs.close()
logconn.close()
else:
#we can't put this in main try block because an error connecting
#to the logging DB would be indistinguishable from an error in
#the mainquery
#We can't put this after the whole try: except: finally: block
#because then we don't know if the query was successful or not
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of successful query")
logcurs.close()
logconn.close()
#do something in response to successful query
except DBError:
#This DBError is because of a problem with the logging database, but
#we can't let that crash the whole thread over what might be a
#temporary network glitch
finally:
curs.close()
conn.close()
#other cleanup if necessary like telling the queue the task is finished
Звичайно, якщо ви можете розрізняти можливі винятки, які можуть бути викинуті, вам не доведеться використовувати це, але якщо код, що реагує на вдалий фрагмент коду, може викинути той самий виняток, що і успішний фрагмент, і ви не можете просто відпустіть другий можливий виняток або повертайтеся негайно до успіху (що могло б вбити нитку в моєму випадку), тоді це стане в нагоді.
elseБлок часто може існувати на додаток до функціональності , яка відбувається в кожному exceptблоці.
try:
test_consistency(valuable_data)
except Except1:
inconsistency_type = 1
except Except2:
inconsistency_type = 2
except:
# Something else is wrong
raise
else:
inconsistency_type = 0
"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""
У цьому випадку inconsistency_typeвстановлюється у кожному, крім блоку, так що поведінка доповнюється у випадку без помилок у else.
Звичайно, я описую це як зразок, який колись може з’явитися у вашому власному коді. У цьому конкретному випадку ви просто все-таки встановите inconsistency_type0 перед tryблоком.
Ось ще одне місце, де я люблю використовувати цю схему:
while data in items:
try
data = json.loads(data)
except ValueError as e:
log error
else:
# work on the `data`
continueзамість цього - шаблон "вирватися рано". Це дозволяє скинути пункт "else" та його відступ, що полегшує читання коду.
Один із сценаріїв використання, який я можу придумати, - це непередбачувані винятки, які можна обійти, якщо спробувати ще раз. Наприклад, коли операції в блоці спробу включають випадкові числа:
while True:
try:
r = random.random()
some_operation_that_fails_for_specific_r(r)
except Exception:
continue
else:
break
Але якщо виняток можна передбачити, завжди слід вибирати перевірку заздалегідь над винятком. Однак не все можна передбачити, тому цей шаблон коду має своє місце.
breakвнутрішню tryсторону в кінці, яка чистіша IMO, і вона вам не потрібна else. Крім того, continueце не дуже потрібно, ви можете просто pass.
Я вважаю elseкорисним для роботи з можливо неправильним файлом конфігурації:
try:
value, unit = cfg['lock'].split()
except ValueError:
msg = 'lock monitoring config must consist of two words separated by white space'
self.log('warn', msg)
else:
# get on with lock monitoring if config is ok
Виняток, що читає lockконфігурацію, відключає моніторинг блокування, а ValueErrors записує корисне попередження.
Припустимо, ваша логіка програмування залежить від того, чи має словник запис із заданим ключем. Ви можете перевірити результат, dict.get(key)використовуючи if... else...конструкт, або ви можете зробити:
try:
val = dic[key]
except KeyError:
do_some_stuff()
else:
do_some_stuff_with_val(val)
Я б додав ще один випадок використання, який здається прямо перед обробкою сеансів БД:
# getting a DB connection
conn = db.engine.connect()
# and binding to a DB session
session = db.get_session(bind=conn)
try:
# we build the query to DB
q = session.query(MyTable).filter(MyTable.col1 == 'query_val')
# i.e retrieve one row
data_set = q.one_or_none()
# return results
return [{'col1': data_set.col1, 'col2': data_set.col2, ...}]
except:
# here we make sure to rollback the transaction,
# handy when we update stuff into DB
session.rollback()
raise
else:
# when no errors then we can commit DB changes
session.commit()
finally:
# and finally we can close the session
session.close()
else:Блок збиває з пантелику , і (майже) марно. Це також частина forта whileтверджень.
Насправді, навіть за ifтвердженням, зловмисники else:можуть зловживати по-справжньому жахливими способами, створюючи помилки, які дуже важко знайти.
Розглянемо це.
if a < 10:
# condition stated explicitly
elif a > 10 and b < 10:
# condition confusing but at least explicit
else:
# Exactly what is true here?
# Can be hard to reason out what condition is true
Подумайте двічі else:. Це взагалі проблема. Уникайте цього, окрім ifзаяви, і навіть тоді розглядайте питання документування elseумови - щоб зробити це явним.
if x > 0: return "yes"і if x <= 0: return "no". Зараз людина приходить і змінює одну з умов сказати, x > 1але забуває змінити іншу. Як це зменшити кількість помилок, які будуть вчинені. if elseЗастереження іноді багато рядків один від одного. DRY - це хороша практика, набагато частіше, ніж ні, насправді. (вибачте за подвійний пост).