파이썬 : __init__ 내에서 예외를 발생시키는 것이 나쁜 형태입니까?


128

내부에서 예외를 발생시키는 것이 나쁜 형태로 간주 __init__됩니까? 그렇다면 특정 클래스 변수가 None잘못된 유형 으로 초기화 될 때 허용되는 오류를 던지는 방법은 무엇입니까?


C에서는 소멸자에서 예외를 발생시키는 것이 좋지 않지만 생성자는 괜찮습니다.
Calyth

6
@Calyth, 당신이 평균 C ++ - C.에는 생성자 또는 소멸자가없는
알렉스 마르 텔리는

4
... 또는 그 문제에 대한 예외.
Matt Wilding

@Calyth : lol, 무고한 오타가 만든 무의미한 진술을 제거하십시오 ;-)
lpapp

4
@lpapp 예. C ++. FML. 그리고 그 의견을 편집 할 수 없었습니다. 그래서 인터넷은 나의 관용을 문서화 할 것이다;)
Calyth

답변:


159

예외를 발생시키는 __init__()것은 절대적으로 좋습니다. 생성자 내에서 오류 조건을 나타내는 다른 좋은 방법은 없으며 표준 라이브러리에는 개체를 빌드 할 때 예외가 발생할 수있는 수백 가지의 예제가 있습니다.

물론 발생하는 오류 클래스는 사용자에게 달려 있습니다. ValueError생성자에 잘못된 매개 변수가 전달 된 경우 가장 좋습니다.


14
생성자에서 가장 많이 사용되는 예외는 ValueErrorTypeError입니다.
Denis Otkidach

9
그것을 지적하는 것은 __init__생성자, 그 초 기자입니다. 행을 편집하고 싶을 수도 있습니다 . 생성자 내에서 오류 조건을 나타내는 다른 좋은 방법은 없습니다 ..
Haris

26

생성자에서 오류를 표시하는 유일한 올바른 방법은 예외를 발생시키는 것입니다. 그렇기 때문에 C ++ 및 예외 안전을 염두에두고 설계된 다른 객체 지향 언어에서 객체의 생성자에 예외가 발생하면 소멸자가 호출되지 않습니다 (객체 초기화가 불완전 함을 의미 함). 파이썬과 같은 스크립팅 언어에서는 그렇지 않습니다. 예를 들어, 다음 코드는 socket.connect ()가 실패하면 AttributeError를 발생시킵니다.

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()

그 이유는 연결 시도가 실패한 후 스트림 속성이 초기화되기 전에 불완전한 객체의 소멸자가 호출되기 때문입니다. 생성자로부터 예외를 던지는 것을 피해서는 안됩니다. 파이썬에서 완전히 예외 안전 코드를 작성하는 것이 어렵다고 말하고 있습니다. 일부 파이썬 개발자는 소멸자를 사용하지 않는 것이 좋지만 또 다른 논쟁의 문제입니다.


이 답변은 정말 유용합니다. "녹색 표시 등"에 대해서만 말하는 것이 아니라 "파괴자"의 예를 언급합니다.
lpapp

파이썬 코드가 실패합니다 __del__ 가 잘못 작성 . this->p_socket->close()C ++의 소멸자에서 똑같은 문제가 발생했습니다 . C ++에서는 그렇게하지 않을 것입니다. 멤버 객체가 스스로 파괴되도록 할 것입니다. 파이썬에서도 똑같이하십시오.
Eric

1
@Eric C ++은 제대로 초기화되지 않은 객체를 파괴하지 않기 때문에 C ++ 에서 문제가 발생 하지 않습니다 . 실제로 C ++ 에서는 생성자에 리소스할당하고 소멸자에 할당을 해제 하는 것은 매우 일반적인 관용구입니다 . 멤버 객체가 자체 소멸 (소멸자의 리소스 할당 해제)을 제안하면 멤버 클래스를 작성할 때도 동일한 문제가 발생합니다.
Seppo Enarvi

11

나는 그것이 나쁜 형식이어야한다는 이유를 보지 못했습니다.

반대로, 오류 코드를 반환하는 대신 예외가 잘 수행되는 것으로 알려진 것 중 하나는 일반적 으로 생성자 가 오류 코드를 반환 할 수 없다는 것입니다. 따라서 적어도 C ++과 같은 언어에서는 예외를 발생시키는 것이 오류를 알리는 유일한 방법입니다.


6

표준 라이브러리는 다음과 같이 말합니다.

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

내장 ValueError예외에 대한 완벽한 사례라고 생각해야합니다 .


2

위의 모든 내용에 동의합니다.

예외를 발생시키는 것 외에 객체를 초기화 할 때 무언가 잘못되었다는 신호를 보내는 다른 방법은 없습니다.

클래스의 상태가 그 클래스의 입력에 전적으로 의존하는 대부분의 프로그램 클래스에서 우리는 어떤 종류의 ValueError 또는 TypeError가 발생할 것으로 기대할 수 있습니다.

네트워크 장치를 사용할 수 없거나 캔버스 개체를 쓸 수없는 경우 부작용이있는 클래스 (예 : 네트워킹 또는 그래픽을 수행하는 클래스)에서 초기화 오류가 발생할 수 있습니다. 실패 조건에 대해 가능한 한 빨리 알고 싶어하기 때문에 이것은 나에게 합리적입니다.


2

init에서 오류를 발생시키는 것은 피할 수 없지만 init에서 너무 많은 작업을 수행하는 것은 나쁜 스타일입니다. 팩토리 또는 의사 팩토리 (설정된 오브젝트를 리턴하는 간단한 클래스 메소드)를 고려해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.