Python 3의 클래스 상속 이해


소개

객체 지향 프로그래밍은 재사용 가능한 코드 패턴을 생성하여 개발 프로젝트의 중복성을 줄입니다. 객체 지향 프로그래밍이 재활용 가능한 코드를 달성하는 한 가지 방법은 하나의 하위 클래스가 다른 기본 클래스의 코드를 활용할 수 있는 상속을 통해서입니다.

이 튜토리얼은 부모 클래스와 자식 클래스가 작동하는 방법, 메서드와 속성을 재정의하는 방법, super() 함수를 사용하는 방법 및 다중 상속을 사용합니다.

전제 조건

컴퓨터나 서버에 Python 3가 설치되어 있고 프로그래밍 환경이 설정되어 있어야 합니다. 프로그래밍 환경이 설정되지 않은 경우 운영 체제(Ubuntu, CentOS, Debian 등)에 적합한 서버의 프로그래밍 환경에 대한 설치 및 설정 가이드를 참조할 수 있습니다.

상속이란 무엇입니까?

상속은 클래스가 다른 클래스 내에서 생성된 코드를 사용하는 경우입니다. 생물학의 관점에서 유전을 생각하면 부모로부터 특정 특성을 물려받은 자녀를 생각할 수 있습니다. 즉, 자식은 부모의 키나 눈 색깔을 물려받을 수 있습니다. 자녀도 부모와 같은 성을 공유할 수 있습니다.

자식 클래스 또는 하위 클래스라고 하는 클래스는 부모 클래스 또는 기본 클래스에서 메서드와 변수를 상속합니다.

우리는 , 높이eye_color에 대한 클래스 변수가 있는 Parent라는 부모 클래스를 생각할 수 있습니다. 자식 클래스 ChildParent에서 상속합니다.

Child 하위 클래스는 Parent 기본 클래스에서 상속되기 때문에 Child 클래스는 Parent의 코드를 재사용할 수 있습니다. 프로그래머가 더 적은 수의 코드를 사용하고 중복성을 줄일 수 있습니다.

부모 클래스

부모 또는 기본 클래스는 자식 또는 하위 클래스가 기반으로 할 수 있는 패턴을 만듭니다. 부모 클래스를 사용하면 매번 동일한 코드를 다시 작성하지 않고도 상속을 통해 자식 클래스를 만들 수 있습니다. 모든 클래스는 상위 클래스로 만들 수 있으므로 템플릿이 아닌 각각의 완전한 기능을 갖춘 클래스입니다.

Personal_accountBusiness_account 하위 클래스가 있는 일반적인 Bank_account 상위 클래스가 있다고 가정해 보겠습니다. 인출 및 입금 방법과 같이 개인 계정과 비즈니스 계정 간의 많은 메서드는 유사하므로 Bank_account의 부모 클래스에 속할 수 있습니다. Business_account 하위 클래스에는 비즈니스 기록 및 양식을 수집하는 방법과 employee_identification_number 변수를 포함하여 고유한 메서드가 있습니다.

마찬가지로 Animal 클래스에는 eating()sleeping() 메서드가 있을 수 있으며 Snake 하위 클래스에는 다음이 포함될 수 있습니다. 고유한 hissing()slithering() 메서드.

나중에 물고기 유형을 하위 클래스로 구성하는 데 사용할 Fish 상위 클래스를 만들어 보겠습니다. 이 물고기들은 특성 외에도 이름과 성을 가지고 있습니다.

정보: 이 자습서의 예제 코드를 따라하려면 python3 명령을 실행하여 로컬 시스템에서 Python 대화형 셸을 엽니다. 그런 다음 >>> 프롬프트 뒤에 추가하여 예제를 복사, 붙여넣기 또는 편집할 수 있습니다.

fish.py라는 새 파일을 만들고 __init__() 생성자 메서드로 시작하여 first_name으로 채우고 각 Fish 개체 또는 하위 클래스에 대한 last_name 클래스 변수.

class Fish:
    def __init__(self, first_name, last_name="Fish"):
        self.first_name = first_name
        self.last_name = last_name

우리는 \Fish\ 문자열을 사용하여 last_name 변수를 초기화했습니다. 대부분의 물고기가 이것을 성으로 사용한다는 것을 알고 있기 때문입니다.

다른 방법도 추가해 보겠습니다.

class Fish:
    def __init__(self, first_name, last_name="Fish"):
        self.first_name = first_name
        self.last_name = last_name

    def swim(self):
        print("The fish is swimming.")

    def swim_backwards(self):
        print("The fish can swim backwards.")

우리는 메서드 swim()swim_backwards()Fish 클래스에 추가하여 모든 하위 클래스도 사용할 수 있도록 했습니다. 이러한 방법.

우리가 만들 물고기의 대부분은 연골 물고기로 간주되기 때문에(연골로 만들어진 골격을 가지고 있기 때문에) __init__() 메서드에 몇 가지 속성을 더 추가할 수 있습니다.

class Fish:
    def __init__(self, first_name, last_name="Fish",
                 skeleton="bone", eyelids=False):
        self.first_name = first_name
        self.last_name = last_name
        self.skeleton = skeleton
        self.eyelids = eyelids

    def swim(self):
        print("The fish is swimming.")

    def swim_backwards(self):
        print("The fish can swim backwards.")

부모 클래스를 구축하는 것은 다른 클래스를 구축하는 것과 동일한 방법론을 따르지만, 자식 클래스를 생성한 후 자식 클래스가 사용할 수 있는 방법에 대해 생각한다는 점만 다릅니다.

하위 클래스

자식 또는 하위 클래스는 부모 클래스에서 상속되는 클래스입니다. 즉, 각 자식 클래스는 부모 클래스의 메서드와 변수를 사용할 수 있습니다.

예를 들어, Fish 클래스를 하위 클래스로 만드는 Goldfish 자식 클래스는 에 선언된 swim() 메서드를 사용할 수 있습니다. 선언할 필요 없이 낚시합니다.

각 자식 클래스를 부모 클래스의 클래스로 생각할 수 있습니다. 즉, Rhombus라는 하위 클래스와 평행사변형이라는 상위 클래스가 있는 경우 Rhombus라고 말할 수 있습니다. 금붕어물고기인 것처럼 평행사변형입니다.

자식 클래스의 첫 번째 줄은 자식 클래스에 매개 변수로 부모 클래스를 전달해야 하므로 자식 클래스가 아닌 클래스와 약간 다르게 보입니다.

class Trout(Fish):

Trout 클래스는 Fish 클래스의 자식입니다. 괄호 안에 물고기라는 단어가 포함되어 있기 때문에 이를 알 수 있습니다.

자식 클래스를 사용하면 더 많은 메서드를 추가하거나 기존 부모 메서드를 재정의하거나 pass 키워드를 사용하여 기본 부모 메서드를 수락하도록 선택할 수 있습니다. 이 경우에는 다음과 같이 수행합니다.

...
class Trout(Fish):
    pass

이제 추가 메서드를 정의하지 않고도 Trout 개체를 만들 수 있습니다.

...
class Trout(Fish):
    pass

terry = Trout("Terry")
print(terry.first_name + " " + terry.last_name)
print(terry.skeleton)
print(terry.eyelids)
terry.swim()
terry.swim_backwards()

Fish 클래스의 각 메소드를 사용하는 Trout 객체 terry를 만들었습니다. Trout 자식 클래스. 다른 모든 변수가 초기화되었기 때문에 \Terry\ 값을 first_name 변수에 전달하기만 하면 되었습니다.

프로그램을 실행하면 다음과 같은 결과가 나타납니다.

Output
Terry Fish bone False The fish is swimming. The fish can swim backwards.

다음으로 자체 메서드를 포함하는 다른 자식 클래스를 만들어 보겠습니다. 우리는 이 클래스를 클라운피시라고 부르며, 이 클래스의 특수 메서드를 통해 말미잘과 함께 살 수 있습니다.

...
class Clownfish(Fish):

    def live_with_anemone(self):
        print("The clownfish is coexisting with sea anemone.")

다음으로 클라운피시 개체를 만들어 어떻게 작동하는지 살펴보겠습니다.

...
casey = Clownfish("Casey")
print(casey.first_name + " " + casey.last_name)
casey.swim()
casey.live_with_anemone()

프로그램을 실행하면 다음과 같은 결과가 나타납니다.

Output
Casey Fish The fish is swimming. The clownfish is coexisting with sea anemone.

출력은 Clownfish 개체 caseyFish 메서드 __init__()를 사용할 수 있음을 보여줍니다. swim()live_with_anemone()의 자식 클래스 메서드.

Trout 객체에서 live_with_anemone() 메서드를 사용하려고 하면 오류가 발생합니다.

Output
terry.live_with_anemone() AttributeError: 'Trout' object has no attribute 'live_with_anemone'

이는 live_with_anemone() 메서드가 Clownfish 자식 클래스에만 속하고 Fish 부모 클래스에는 속하지 않기 때문입니다.

하위 클래스는 자신이 속한 상위 클래스의 메서드를 상속하므로 각 하위 클래스는 프로그램 내에서 해당 메서드를 사용할 수 있습니다.

부모 메서드 재정의

지금까지 우리는 pass 키워드를 사용하여 모든 부모 클래스 Fish 동작을 상속하는 자식 클래스 Trout을 살펴보았습니다. 다른 자식 클래스 클라운피시는 모든 부모 클래스 동작을 상속하고 자식 클래스에 고유한 고유 메서드도 생성했습니다. 그러나 때로는 부모 클래스 동작 중 일부를 사용하고 싶지만 전부는 사용하지 않으려는 경우가 있습니다. 부모 클래스 메서드를 변경할 때 재정의합니다.

상위 및 하위 클래스를 구성할 때 재정의로 인해 불필요하거나 중복되는 코드가 생성되지 않도록 프로그램 설계를 염두에 두는 것이 중요합니다.

Fish 상위 클래스의 Shark 하위 클래스를 생성합니다. 주로 경골어를 만들겠다는 생각으로 Fish 클래스를 만들었기 때문에 대신 연골어류인 Shark 클래스를 조정해야 합니다. 프로그램 설계 측면에서 뼈가 없는 물고기가 둘 이상인 경우 이 두 가지 유형의 물고기 각각에 대해 별도의 클래스를 만들고 싶을 것입니다.

경골어류와 달리 상어는 뼈대신 연골로 만들어진 뼈대를 가지고 있다. 그들은 또한 눈꺼풀이 있고 뒤로 헤엄칠 수 없습니다. 그러나 상어는 가라앉음으로써 스스로 뒤로 움직일 수 있습니다.

이를 고려하여 __init__() 생성자 메서드와 swim_backwards() 메서드를 재정의할 것입니다. 상어는 헤엄칠 수 있는 물고기이기 때문에 swim() 메서드를 수정할 필요가 없습니다. 이 하위 클래스를 검토해 보겠습니다.

...
class Shark(Fish):
    def __init__(self, first_name, last_name="Shark",
                 skeleton="cartilage", eyelids=True):
        self.first_name = first_name
        self.last_name = last_name
        self.skeleton = skeleton
        self.eyelids = eyelids

    def swim_backwards(self):
        print("The shark cannot swim backwards, but can sink backwards.")

__init__() 메서드에서 초기화된 매개변수를 재정의하여 last_name 변수가 이제 문자열 \Shark\와 동일하게 설정되었습니다. skeleton 변수는 이제 문자열 \cartilage\와 동일하게 설정되고 eyelid 변수는 이제 부울 값 True로 설정됩니다. . 클래스의 각 인스턴스는 이러한 매개 변수를 재정의할 수도 있습니다.

swim_backwards() 메서드는 이제 Fish 상위 클래스의 문자열과 다른 문자열을 인쇄합니다. 상어는 경골어가 할 수 있는 방식으로 뒤로 헤엄칠 수 없기 때문입니다.

이제 Fish 부모 클래스의 swim() 메서드를 계속 사용할 Shark 자식 클래스의 인스턴스를 만들 수 있습니다.

...
sammy = Shark("Sammy")
print(sammy.first_name + " " + sammy.last_name)
sammy.swim()
sammy.swim_backwards()
print(sammy.eyelids)
print(sammy.skeleton)

이 코드를 실행하면 다음과 같은 결과가 표시됩니다.

Output
Sammy Shark The fish is swimming. The shark cannot swim backwards, but can sink backwards. True cartilage

Shark 자식 클래스는 Fish 부모 클래스의 __init__()swim_backwards() 메서드를 성공적으로 재정의했습니다. 또한 부모 클래스의 swim() 메서드도 상속합니다.

다른 것보다 더 고유한 자식 클래스의 수가 제한되어 있는 경우 부모 클래스 메서드를 재정의하는 것이 유용할 수 있습니다.

슈퍼() 함수

super() 함수를 사용하면 클래스 개체에서 덮어쓴 상속된 메서드에 액세스할 수 있습니다.

super() 함수를 사용할 때 부모 메서드를 자식 메서드로 호출하여 사용합니다. 예를 들어 부모 메서드의 한 측면을 특정 기능으로 재정의하고 원래 부모 메서드의 나머지 부분을 호출하여 메서드를 완료할 수 있습니다.

학생을 평가하는 프로그램에서 Grade 상위 클래스에서 상속되는 Weighted_grade에 대한 하위 클래스를 원할 수 있습니다. 자식 클래스 Weighted_grade에서, 우리는 가중 등급을 계산하는 기능을 포함하기 위해 부모 클래스의 calculate_grade() 메서드를 재정의할 수 있지만 나머지는 계속 유지합니다. 원래 클래스의 기능. super() 함수를 호출하면 이를 달성할 수 있습니다.

super() 함수는 __init__() 메서드 내에서 가장 일반적으로 사용됩니다. 그 이유는 여기에서 자식 클래스에 일부 고유성을 추가한 다음 초기화를 완료해야 할 가능성이 높기 때문입니다. 부모로부터.

이것이 어떻게 작동하는지 보기 위해 Trout 자식 클래스를 수정해 보겠습니다. 송어는 일반적으로 민물고기이므로 __init__() 메서드에 water 변수를 추가하고 문자열 \freshwater\와 동일하게 설정합니다. 그러나 부모 클래스의 나머지 변수와 매개변수는 유지합니다.

...
class Trout(Fish):
    def __init__(self, water = "freshwater"):
        self.water = water
        super().__init__(self)
...

Trout 자식 클래스의 __init__() 메서드를 재정의하여 이미 정의된 __init__()의 다른 구현을 제공합니다. 상위 클래스 물고기. Trout 클래스의 __init__() 메서드 내에서 Fish__init__() 메서드를 명시적으로 호출했습니다. 수업.

메서드를 재정의했기 때문에 더 이상 first_nameTrout에 매개 변수로 전달할 필요가 없으며 매개 변수를 전달한 경우 를 재설정합니다. 담수 대신. 따라서 개체 인스턴스에서 변수를 호출하여 first_name을 초기화합니다.

이제 부모 클래스의 초기화된 변수를 호출하고 고유한 자식 변수도 사용할 수 있습니다. 이것을 Trout의 인스턴스에서 사용해 봅시다:

...
terry = Trout()

# Initialize first name
terry.first_name = "Terry"

# Use parent __init__() through super()
print(terry.first_name + " " + terry.last_name)
print(terry.eyelids)

# Use child __init__() override
print(terry.water)

# Use parent swim() method
terry.swim()
Output
Terry Fish False freshwater The fish is swimming.

출력은 Trout 하위 클래스의 객체 terry가 하위 특정 __init__() 변수 water와 동시에 Fish 부모 __init__() first_name, last_name 및 눈꺼풀.

내장 Python 함수 super()를 사용하면 자식 클래스에서 해당 메서드의 특정 측면을 재정의할 때에도 부모 클래스 메서드를 활용할 수 있습니다.

다중 상속

다중 상속은 클래스가 둘 이상의 부모 클래스에서 특성과 메서드를 상속할 수 있는 경우입니다. 이렇게 하면 프로그램의 중복성을 줄일 수 있지만 어느 정도의 복잡성과 모호성을 도입할 수 있으므로 전체 프로그램 설계를 고려하여 수행해야 합니다.

다중 상속이 작동하는 방식을 보여주기 위해 Coral 클래스와 Sea_anemone 클래스에서 상속하는 Coral_reef 하위 클래스를 만들어 보겠습니다. 각각에 메서드를 생성한 다음 Coral_reef 하위 클래스에서 pass 키워드를 사용할 수 있습니다.

class Coral:

    def community(self):
        print("Coral lives in a community.")


class Anemone:

    def protect_clownfish(self):
        print("The anemone is protecting the clownfish.")


class CoralReef(Coral, Anemone):
    pass

Coral 클래스에는 한 줄을 인쇄하는 community()라는 메서드가 있고, Anemone 클래스에는 protect_clownfish()라는 메서드가 있습니다. 다른 줄을 인쇄합니다. 그런 다음 두 클래스를 모두 상속 튜플로 호출합니다. 이는 CoralReef가 두 개의 상위 클래스에서 상속됨을 의미합니다.

이제 CoralReef 개체를 인스턴스화하겠습니다.

...
great_barrier = CoralReef()
great_barrier.community()
great_barrier.protect_clownfish()

개체 great_barrierCoralReef 개체로 설정되며 두 부모 클래스 모두에서 메서드를 사용할 수 있습니다. 프로그램을 실행하면 다음과 같은 결과가 표시됩니다.

Output
Coral lives in a community. The anemone is protecting the clownfish.

결과는 두 부모 클래스의 메서드가 자식 클래스에서 효과적으로 사용되었음을 보여줍니다.

다중 상속을 통해 자식 클래스에서 둘 이상의 부모 클래스의 코드를 사용할 수 있습니다. 동일한 메서드가 여러 부모 메서드에 정의된 경우 자식 클래스는 튜플 목록에 선언된 첫 번째 부모 메서드를 사용합니다.

효과적으로 사용할 수 있지만 다중 상속은 우리 프로그램이 모호해지거나 다른 프로그래머가 이해하기 어렵게 되지 않도록 주의해야 합니다.

결론

이 자습서에서는 부모 클래스와 자식 클래스 구성, 자식 클래스 내의 부모 메서드 및 특성 재정의, super() 함수 사용, 자식 클래스가 여러 부모 클래스에서 상속할 수 있도록 하는 방법을 살펴보았습니다.

개체 지향 코딩의 상속을 통해 소프트웨어 개발의 DRY(반복하지 마십시오) 원칙을 준수할 수 있으므로 더 적은 코드와 반복으로 더 많은 작업을 수행할 수 있습니다. 상속은 또한 프로그래머가 코드가 효과적이고 명확하도록 만들기 위해 프로그램을 설계하는 방법에 대해 생각하게 만듭니다.