Подтвердить что ты не робот

Python: Это плохая форма для исключения исключений в течение __init__?

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

4b9b3361

Ответ 1

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

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

Ответ 2

Это правда, что единственный правильный способ указать ошибку в конструкторе - это создание исключения. Именно поэтому на С++ и в других объектно-ориентированных языках, которые были разработаны с учетом безопасности исключений, деструктор не вызывается, если исключение выбрано в конструкторе объекта (что означает, что инициализация объекта является неполной). Это часто бывает не в языках сценариев, таких как 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 вообще избегают использования деструкторов, но это вопрос других дебатов.

Ответ 3

Я не вижу причин, чтобы это была плохая форма.

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

Ответ 4

В стандартной библиотеке написано:

>>> 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'

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

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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