При використанні PyCharm IDE використання except:
без винятку типу запускає нагадування від IDE про те, що це положення про виключення Too broad
.
Чи слід ігнорувати цю пораду? Або це Pythonic завжди конкретний тип виключення?
При використанні PyCharm IDE використання except:
без винятку типу запускає нагадування від IDE про те, що це положення про виключення Too broad
.
Чи слід ігнорувати цю пораду? Або це Pythonic завжди конкретний тип виключення?
Відповіді:
Майже завжди краще вказати чіткий тип виключення. Якщо ви користуєтесь головою except:
пропозицією, ви можете знайти інші винятки, ніж ті, які ви очікуєте зловити - це може приховати помилки або ускладнити налагодження програм, коли вони не роблять те, що ви очікуєте.
Наприклад, якщо ви вставляєте рядок у базу даних, ви можете захопити виняток, який вказує на те, що рядок вже існує, тому ви можете зробити оновлення.
try:
insert(connection, data)
except:
update(connection, data)
Якщо ви вказали голий except:
, ви також побачите помилку сокета, що вказує на те, що сервер бази даних перейшов. Найкраще виловлювати лише винятки, з якими ви знаєте, як впоратися - програмі часто краще відмовитись від точки винятку, ніж продовжувати, але вести себе дивними несподіваними способами.
Один випадок, коли ви, можливо, захочете використовувати голий, except:
знаходиться на найвищому рівні програми, яку потрібно завжди виконувати, як, наприклад, мережевий сервер. Але тоді вам потрібно бути дуже обережним, щоб реєструвати винятки, інакше буде неможливо розібратися, що відбувається не так. В основному, у програмі, яка це робить, має бути не менше одного місця.
Наслідком всього цього є те, що ваш код ніколи не повинен робити, raise Exception('some message')
оскільки він змушує клієнтський код використовувати except:
(або except Exception:
це майже так само погано). Ви повинні визначити виняток, характерний для проблеми, про яку ви хочете подати сигнал (можливо, успадковуючи якийсь вбудований підклас винятків, як ValueError
або TypeError
). Або слід підняти конкретний вбудований виняток. Це дає змогу користувачам вашого коду бути обережними у пошуку винятків, з якими вони хочуть працювати.
except:
також ловить (серед іншого) NameError
і AttributeError
, якщо ви неправильно написали щось у try
блоці (наприклад, ваша функція "вставки" насправді викликається insert_one
тому, що хтось не цінував послідовність стільки, скільки слід), це завжди мовчки намагається update()
.
main()
)?
except Exception:
зловить NameError
і AttributeError
теж. Те, що робить голою except:
настільки погано, це те, що вона ловить речі, які не мають спійманого бізнесу, наприклад SystemExit
(піднятий під час дзвінка exit
або sys.exit
, і тепер ви перешкодили наміченому виходу) та KeyboardInterrupt
(знову ж таки, якщо користувач вдарив Ctrl-C
, ви, ймовірно, не хочете продовжувати бігати лише для того, щоб насупити їх). Тільки останній має будь-який реальний сенс ловити, і його слід чітко ловити. Принаймні, except Exception:
дозвольте цим двом нормально поширюватися.
Ви не повинні ігнорувати поради, які дає вам перекладач.
З посібника зі стилю PEP-8 для Python:
Уловлюючи винятки, зазначайте конкретні винятки, коли це можливо, замість використання голого, за винятком: пункту.
Наприклад, використовуйте:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
Оголене, за винятком: пункт вилучить виключення SystemExit і KeyboardInterrupt, що ускладнить переривання програми з Control-C і може замаскувати інші проблеми. Якщо ви хочете зафіксувати всі винятки, які посилаються на помилки програмної програми, використовуйте крім винятку: (оголене, за винятком випадків, еквівалентне, крім BaseException :).
Хорошим правилом є обмеження використання голих "за винятком" пунктів на два випадки:
Якщо обробник винятків буде роздруковувати або реєструвати прослідкування; принаймні користувач буде знати, що сталася помилка. Якщо код потребує певної роботи з очищення, але потім дозволяє винятку поширюватися вгору з підвищенням. спробуйте ... нарешті, може бути кращий спосіб впоратися з цією справою.
Це не специфічно для Python.
Вся суть винятків полягає в тому, щоб вирішити проблему якомога ближче до місця, де вона була викликана.
Таким чином, ви зберігаєте код, який у надзвичайних обставинах може викликати проблему та вирішення "поруч".
Вся справа в тому, що ви не можете знати всіх винятків, які можуть бути викинуті фрагментом коду. Все, що ви можете знати, це те, що якщо це, скажімо, файл не знайдений виняток, то ви можете захопити його та запропонувати користувачеві отримати функцію, яка виконує або скасовує функцію.
Якщо ви поставите спробу лову навколо цього, то незалежно від того, яка проблема була у вашому розпорядженні файлів (лише читання, дозволи, UAC, насправді не pdf тощо), кожен потрапить до вашого файлу не знайденого улову та вашого користувача кричить "але це там, цей код - лайно"
Зараз є декілька ситуацій, коли ви можете зловити все, але вибирати їх слід свідомо.
Вони вловлюють, скасовують деякі локальні дії (наприклад, створення або блокування ресурсу (відкриття файлу на диску для запису, наприклад), потім ви кидаєте виняток знову, щоб вирішуватись на більш високому рівні)
Інший, який ти - тобі не байдуже, чому пішло не так Наприклад, друк. Можливо, у вас є улов у всьому світі, щоб сказати, що з принтером є якась проблема, будь ласка, розіб'йтесь, а не вбивайте програму через неї. Она подібно марно, якщо ваш код виконав ряд окремих завдань за допомогою якогось розкладу, ви не хочете, щоб вся справа загинула, оскільки одна з задач не вдалася.
Примітка Якщо ви робите вище, я не можу порекомендувати якийсь журнал винятків, наприклад, спробувати кінець журналу, досить високо.
Ви також будете ловити, наприклад, Control-C з цим, тому не робіть цього, якщо ви не кинете його ще раз. Однак у такому випадку вам краще скористатися "нарешті".
Завжди вказуйте тип винятку, існує багато типів ви не хочете зловити, як SyntaxError
, KeyboardInterrupt
, і MemoryError
т.д.
except Exception:
вдалося б уникнути перерахованих вище типів, які ми не хочемо ловити?
except Exception
добре.
except Exception
ловить SyntaxError
і MemoryError
тому, що це їх базовий клас. KeyboardInterrupt
, SystemExit
(підняв sys.exit()
) не спійманий (вони є негайними підкласами BaseException)
Ось місця, де я користуюся, окрім без типу
Це головне використання мого коду для неперевірених винятків
Я завжди додаю це, щоб виробничий код не розсипав стеки
У мене є два способи зробити це:
Я вважаю за краще це таким чином, мені легше виявити, які винятки мали бути належним чином виловлені: я краще "бачу" проблему, коли виняток нижчого рівня реєструється вищим рівнем
Деякі колеги віддають перевагу цьому способу, оскільки він зберігає винятки нижчого рівня у функціях нижчого рівня, де вони "належать".
Спробуйте це:
try:
#code
except ValueError:
pass
Я отримав відповідь за цим посиланням, якщо хтось інший зіткнувся з цим питанням Перевірте це