Python: Это плохая форма для создания исключений внутри __init__? - PullRequest
105 голосов
/ 02 октября 2009

Считается ли плохой формой возбуждать исключения в пределах __init__? Если так, то каков принятый метод выдачи ошибки, когда определенные переменные класса инициализируются как None или имеют неправильный тип?

Ответы [ 7 ]

136 голосов
/ 02 октября 2009

Повышение исключений в пределах __init__() абсолютно нормально. Нет другого хорошего способа указать состояние ошибки в конструкторе, и в стандартной библиотеке есть сотни примеров, когда создание объекта может вызвать исключение.

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

22 голосов
/ 21 сентября 2011

Это правда, что единственный правильный способ указать на ошибку в конструкторе - вызвать исключение. Вот почему в C ++ и в других объектно-ориентированных языках, которые были разработаны с учетом безопасности исключений, деструктор не вызывается, если в конструктор объекта выдается исключение (что означает, что инициализация объекта не завершена). Это часто не относится к языкам сценариев, таким как Python. Например, следующий код выдает AttributeError в случае сбоя socket.connect ():

class NetworkInterface:
    def __init__(self, address)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect(address)
        self.stream = self.socket.makefile()

    def __del__(self)
        self.stream.close()
        self.socket.close()

Причина в том, что деструктор незавершенного объекта вызывается после неудачной попытки подключения до инициализации атрибута потока. Вы не должны избегать создания исключений из конструкторов, я просто говорю, что на Python сложно написать полностью безопасный код исключений. Некоторые разработчики Python вообще избегают использования деструкторов, но это вопрос другого спора.

11 голосов
/ 02 октября 2009

Не вижу причин, по которым это должно быть плохо.

Напротив, известно, что исключения работают хорошо, в отличие от возврата кодов ошибок, это то, что коды ошибок обычно не могут быть возвращены конструкторами. Так что, по крайней мере, в таких языках, как C ++, возбуждение исключений - единственный способ сообщить об ошибках.

5 голосов
/ 02 октября 2009

Стандартная библиотека говорит:

>>> f = file("notexisting.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'

Кроме того, я не вижу никакой причины, почему это следует считать плохой формой.

3 голосов
/ 02 октября 2009

Мне следует подумать, что это идеальный случай для встроенного исключения ValueError.

2 голосов
/ 16 сентября 2013

В некоторых случаях появление ошибок из init неизбежно, но слишком много работы в init - плохой стиль. Вам следует подумать о создании фабрики или псевдо-фабрики - простого метода класса, который возвращает настроенный объект.

2 голосов
/ 02 октября 2009

Я согласен со всем вышеперечисленным.

Нет другого способа сообщить, что что-то пошло не так при инициализации объекта, кроме как вызвать исключение.

В большинстве программных классов, где состояние класса целиком зависит от входных данных для этого класса, мы можем ожидать, что будет вызвано какое-либо значение ValueError или TypeError.

Классы с побочными эффектами (например, класс, который выполняет сетевое взаимодействие или графику) могут вызвать ошибку в init, если (например) сетевое устройство недоступно или объект холста не может быть записан. Это звучит разумно для меня, потому что часто вы хотите узнать об условиях отказа как можно скорее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...