파이썬에서 상속 및 __init__ 재정의


129

나는 'Dive Into Python'을 읽고 수업 장에서 다음 예제를 제공합니다.

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

그런 다음 작성자는 __init__메소드 를 대체 __init__하려면 올바른 매개 변수를 사용 하여 상위 를 명시 적으로 호출해야 한다고 말합니다 .

  1. 만약 그 FileInfo반에 조상 반이 둘 이상 있다면 어떨까요?
    • 모든 조상 클래스의 __init__메소드 를 명시 적으로 호출해야 합니까?
  2. 또한 재정의하려는 다른 방법 으로이 작업을 수행해야합니까?

3
오버로딩은 재정의와는 별도의 개념입니다.
Dana the Sane

답변:


158

이 책은 서브 클래스-수퍼 클래스 호출과 관련하여 약간 날짜가있다. 내장 클래스의 서브 클래스 화와 관련하여 약간 날짜가 있습니다.

요즘은 다음과 같습니다.

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super(FileInfo, self).__init__()
        self["name"] = filename

다음 사항에 유의하십시오.

  1. 우리는 직접 내장 클래스와 같은 하위 클래스 dict, list, tuple, 등

  2. super함수는이 클래스의 수퍼 클래스 추적 및 적절하게 함수 호출을 처리합니다.


5
더 나은 책 / 자습서를 찾아야합니까?
liewl 2009

2
다중 상속의 경우 super ()가 귀하를 대신하여 모두 추적합니까?
Dana

dict .__ init __ (self), 실제로는 아무 문제가 없습니다-super (...) 호출은보다 일관된 구문을 제공합니다. (다중 상속에서 어떻게 작동하는지 잘 모르겠습니다. 하나의 수퍼 클래스 init 만 찾을 수 있다고 생각합니다 )
David Z

4
super ()의 의도는 다중 상속을 처리하는 것입니다. 단점은 실제로 다중 상속이 여전히 매우 쉽게 중단된다는 것입니다 (< fuhm.net/super-harmful 참조 ).
sth

2
예, 생성자 인수를 취하는 다중 상속 및 기본 클래스의 경우 일반적으로 생성자를 수동으로 호출하는 것을 알 수 있습니다.
Torsten Marek

18

상속 해야하는 각 클래스에서 하위 클래스를 시작할 때 초기화 해야하는 각 클래스의 루프를 실행할 수 있습니다 ... 복사 가능한 예제가 더 잘 이해 될 수 있습니다 ...

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name

2
for 루프 인 Child.__init__이 필요 하지 않은 것 같습니다 . 예제에서 제거해도 여전히 "Grandma"가 인쇄됩니다. 조부모님은 Parent수업에서 처리하지 않습니까?
Adam

4
나는 조부모의 init가 이미 Parent의 init에 의해 처리되고 있다고 생각합니까?
johk95

15

당신은 정말하지 않습니다 통화에 __init__기본 클래스 (들)의 방법을,하지만 당신은 일반적으로 원하는 기본 클래스 작업에 수업 방법의 나머지 부분에 대한 필요가 몇 가지 중요한 초기화를 할 것이기 때문에 그것을 할 수 있습니다.

다른 방법의 경우 의도에 따라 다릅니다. 기본 클래스 비헤이비어에 무언가를 추가하려는 경우 자신의 코드에 추가로 기본 클래스 메서드를 호출하려고합니다. 기본적으로 동작을 변경하려는 경우 기본 클래스의 메소드를 호출하지 않고 파생 된 클래스에서 모든 기능을 직접 구현할 수 있습니다.


4
기술적 완전성을 위해 threading.Thread와 같은 일부 클래스는 부모의 init 호출을 피하려고하면 거대한 오류를 발생시킵니다 .
David Berger

5
이 모든 "베이스의 생성자를 호출 할 필요가 없습니다"라는 말이 극도로 자극적입니다. 내가 아는 언어로 부르지 않아도됩니다. 그들 모두는 멤버를 초기화하지 않음으로써 거의 같은 방식으로 망칠 것입니다. 기본 클래스를 초기화하지 말 것을 제안하는 것은 여러 가지면에서 잘못되었습니다. 클래스에 지금 초기화가 필요하지 않은 경우 나중에 필요합니다. 생성자는 클래스 구조 / 언어 구문의 인터페이스의 일부이므로 올바르게 사용해야합니다. 파생 된 생성자에서 언젠가 호출하는 것이 올바른 사용법입니다. 그렇습니다.
AndreasT 2016 년

2
"기본 클래스를 초기화하지 말 것을 제안하는 것은 여러 가지면에서 잘못되었습니다." 아무도 기본 클래스를 초기화하지 말 것을 제안하지 않았습니다. 답을주의 깊게 읽으십시오. 그것은 의도에 관한 것입니다. 1) 기본 클래스의 초기화 로직을 그대로 유지하려면 파생 클래스의 init 메소드를 재정의하지 마십시오. 2) 기본 클래스에서 초기화 로직을 확장하려면 자체 초기화 메소드를 정의한 후 기본 클래스의 초기화 메소드를 호출하십시오. 3) 기본 클래스의 초기화 로직을 바꾸려면 기본 클래스에서 초기화하지 않고 자신의 init 메소드를 정의하십시오.
wombatonfire

4

FileInfo 클래스에 둘 이상의 조상 클래스가있는 경우 반드시 __init __ () 함수를 모두 호출해야합니다. 또한 소멸자 인 __del __ () 함수에 대해서도 동일하게 수행해야합니다.


2

예, __init__학부모 클래스마다 전화해야합니다 . 두 부모 모두에 존재하는 함수를 재정의하는 경우에도 마찬가지입니다.

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