Python: это плохой тон - вызывать исключения в __init__?
128
Считается ли дурным тоном создавать исключения внутри __init__? Если да, то каков принятый метод выдачи ошибки, когда определенные переменные класса инициализируются как Noneнеправильного типа или имеют неправильный тип?
В языке C вызывать исключение в деструкторе - плохой тон, но с конструктором все должно быть хорошо.
Calyth 02
6
@Calyth, вы имеете в виду C ++ - в C. нет конструкторов или деструкторов
Alex Martelli
4
... или исключения, если на то пошло.
Мэтт Уилдинг
@Calyth: lol, пожалуйста, удалите это бессмысленное заявление, сделанное из-за невинной опечатки ;-)
lpapp 08
4
@lpapp да. C ++. FML. И я не мог редактировать этот комментарий. Так что Интернет должен задокументировать мой идиотизм;)
Calyth
Ответы:
159
Вызов исключений внутри __init__() - это нормально. Нет другого хорошего способа указать состояние ошибки в конструкторе, и в стандартной библиотеке есть сотни примеров, когда построение объекта может вызвать исключение.
Класс ошибки, который нужно поднять, конечно, зависит от вас. ValueErrorлучше всего, если конструктору был передан недопустимый параметр.
Наиболее часто используемые исключения в конструкторе - это ValueErrorи TypeError.
Денис Откидач 02
9
Просто указываю, что __init__это не конструктор, а инициализатор. Возможно, вы захотите отредактировать строку. Нет другого хорошего способа указать состояние ошибки в конструкторе ..
Харис
26
Верно, что единственный правильный способ указать ошибку в конструкторе - это вызвать исключение. Вот почему в C ++ и других объектно-ориентированных языках, которые были разработаны с учетом безопасности исключений, деструктор не вызывается, если в конструкторе объекта возникает исключение (что означает, что инициализация объекта не завершена). В языках сценариев, таких как Python, этого часто не происходит. Например, следующий код вызывает ошибку AttributeError в случае сбоя socket.connect ():
Причина в том, что деструктор неполного объекта вызывается после неудачной попытки подключения, до того, как атрибут потока был инициализирован. Не следует избегать генерации исключений из конструкторов, я просто говорю, что на Python сложно написать полностью безопасный код исключений. Некоторые разработчики Python вообще избегают использования деструкторов, но это уже другой спор.
Этот ответ действительно полезен. Речь идет не просто о «зеленом свете», а упоминается пример с «деструктором».
lpapp
Ваш код Python не работает, __del__потому что он плохо написан. У вас была бы точно такая же проблема, если бы вы делали this->p_socket->close()это в деструкторе на C ++. В C ++ вы бы этого не сделали - вы позволили бы объекту-члену уничтожить себя. Сделайте то же самое в питоне.
Я не вижу причин, по которым это должно быть плохим тоном.
Напротив, одна из вещей, которые, как известно, работают хорошо, в отличие от возврата кодов ошибок, заключается в том, что коды ошибок обычно не могут быть возвращены конструкторами. Так что, по крайней мере, в таких языках, как C ++, создание исключений - единственный способ сигнализировать об ошибках.
>>> f = file("notexisting.txt")Traceback(most recent call last):File"<stdin>", line 1,in<module>IOError:[Errno2]No such file or directory:'notexisting.txt'
Также я не вижу причин, по которым это следует считать плохим тоном.
На самом деле нет другого способа сигнализировать о том, что при инициализации объекта что-то пошло не так, кроме как вызвать исключение.
В большинстве программных классов, где состояние класса полностью зависит от входных данных для этого класса, мы можем ожидать возникновения какой-либо ValueError или TypeError.
Классы с побочными эффектами (например, те, которые работают с сетью или графикой) могут вызвать ошибку в init, если (например) сетевое устройство недоступно или объект холста не может быть записан. Мне это кажется разумным, потому что часто вы хотите узнать об условиях отказа как можно скорее.
В некоторых случаях появление ошибок из init неизбежно, но слишком много работы в init - плохой стиль. Вам следует подумать о создании фабрики или псевдо-фабрики - простого метода классов, который возвращает настроенный объект.
Ответы:
Вызов исключений внутри
__init__()
- это нормально. Нет другого хорошего способа указать состояние ошибки в конструкторе, и в стандартной библиотеке есть сотни примеров, когда построение объекта может вызвать исключение.Класс ошибки, который нужно поднять, конечно, зависит от вас.
ValueError
лучше всего, если конструктору был передан недопустимый параметр.источник
ValueError
иTypeError
.__init__
это не конструктор, а инициализатор. Возможно, вы захотите отредактировать строку. Нет другого хорошего способа указать состояние ошибки в конструкторе ..Верно, что единственный правильный способ указать ошибку в конструкторе - это вызвать исключение. Вот почему в C ++ и других объектно-ориентированных языках, которые были разработаны с учетом безопасности исключений, деструктор не вызывается, если в конструкторе объекта возникает исключение (что означает, что инициализация объекта не завершена). В языках сценариев, таких как Python, этого часто не происходит. Например, следующий код вызывает ошибку AttributeError в случае сбоя socket.connect ():
Причина в том, что деструктор неполного объекта вызывается после неудачной попытки подключения, до того, как атрибут потока был инициализирован. Не следует избегать генерации исключений из конструкторов, я просто говорю, что на Python сложно написать полностью безопасный код исключений. Некоторые разработчики Python вообще избегают использования деструкторов, но это уже другой спор.
источник
__del__
потому что он плохо написан. У вас была бы точно такая же проблема, если бы вы делалиthis->p_socket->close()
это в деструкторе на C ++. В C ++ вы бы этого не сделали - вы позволили бы объекту-члену уничтожить себя. Сделайте то же самое в питоне.Я не вижу причин, по которым это должно быть плохим тоном.
Напротив, одна из вещей, которые, как известно, работают хорошо, в отличие от возврата кодов ошибок, заключается в том, что коды ошибок обычно не могут быть возвращены конструкторами. Так что, по крайней мере, в таких языках, как C ++, создание исключений - единственный способ сигнализировать об ошибках.
источник
Стандартная библиотека говорит:
Также я не вижу причин, по которым это следует считать плохим тоном.
источник
Думаю, это идеальный случай для встроенного
ValueError
исключения.источник
Я согласен со всем вышесказанным.
На самом деле нет другого способа сигнализировать о том, что при инициализации объекта что-то пошло не так, кроме как вызвать исключение.
В большинстве программных классов, где состояние класса полностью зависит от входных данных для этого класса, мы можем ожидать возникновения какой-либо ValueError или TypeError.
Классы с побочными эффектами (например, те, которые работают с сетью или графикой) могут вызвать ошибку в init, если (например) сетевое устройство недоступно или объект холста не может быть записан. Мне это кажется разумным, потому что часто вы хотите узнать об условиях отказа как можно скорее.
источник
В некоторых случаях появление ошибок из init неизбежно, но слишком много работы в init - плохой стиль. Вам следует подумать о создании фабрики или псевдо-фабрики - простого метода классов, который возвращает настроенный объект.
источник