Ответ 1
Я думаю, что общая идея такова: ValueError должен почти всегда обозначать какую-то ошибку клиента (где "клиент" означает программиста, использующего ваш интерфейс). В Python существует два типа исключений высокого уровня:
-
необычные случаи для нормально нормального функционирования кода; клиент не виноват
-
ошибки использования, когда какой-либо интерфейс используется неправильно или через ряд вызовов интерфейса, система достигла несогласованного состояния; время, чтобы обвинить клиента
На мой взгляд, для первого случая имеет смысл создавать иерархии классов исключений, чтобы позволить клиентскому коду осуществлять мелкомасштабный контроль над тем, что делать в необычных случаях.
Во втором случае и ValueError
является примером этого, вы говорите клиенту, что они сделали что-то неправильно. Мелкозернистые иерархии исключений здесь не так важны, потому что код клиента, вероятно, должен быть исправлен для правильной работы (например, сначала передать правильные типы параметров).
TL; DR: просто используйте ValueError
, но включите полезное сообщение (например, raise ValueError("I'm afraid I can't let you do that, Dave. -HAL 9000"
). Не подклассы, если вы искренне ожидаете, что кто-то захочет поймать SubClassError
, но не другие ValueError
s.
С учетом сказанного, как вы уже упоминали, встроенная библиотека Python