본문 바로가기
파이썬

[Python] 파이썬과 객체 지향 프로그래밍

by 책 읽는 개발자_테드 2022. 3. 30.
반응형

파이썬 프로그래밍를 읽고, 정리한 글입니다.

목차

· 객체 지향 프로그래밍

   - 클래스의 형식과 선언

   - 클래스로 새로운 타입 작성하기

· 클래스의 포함관계

· 클래스의 상속관계

   - 클래스 상속관계의 개념

   - 다중 상속의 이해와 구현

   - 추상클래스의 이해와 구현


객체 지향 프로그래밍


· 객체는 상태와 행동을 갖는다.

- 상태(state): 객체가 가지고 있는 속성 또는 특성

- 행동(behavior): 객체가 가지고 있는 기능 또는 할 수 있는 행동

 

· 객체 지향 프로그래밍은 실세계의 제품이 갖는 상태와 행동을 소프트웨어 객체의 멤버변수와 메서드(클래스 내에 포함되어 행위를 표현하는 함소)로 모델링하는 기법이다.

- 실세계의 제품이 갖는 특성이나 상태를 나타내기 위해 멤버변수를 이용한다.

- 이러한 특성이나 상태를 변경시키는 행동을 표현하기 위해 멤버변수의 값을 변경하거나 다른 객체로부터 온 요청에 대한 서비스를 수행하는 메서드를 구현한다.

- 상태를 나타내는 멤버변수와 상태를 변경해 주는 행동을 구현한 메서드를 하나로 묶어 실세계 제품을 소프트웨어 객체로 모델링하고 구현할 수 있다.

 

· 객체는 실세계의 제품이 갖는 구성 요소를 모두 표현할 수 있어야 한다.

 

· 객체 지향 프로그래밍(Object-Oriented Programming)은 조립식 프로그래밍 기법이라고 이해할 수 있다.

 

· 함수형 프로그래밍과 객체 지향 프로그래밍은 잘 어우러진다. 두 기법을 모두 활용하면 좀 더 완성도 높은 프로젝트를 만들 수 있다.

 

파이썬에서 객체란?

· 파이썬은 함수 중심적 언어이면서, 객체 지향 프로그래밍의 표준 기능을 제공하기에 클래스의 포함과 상속 메커니즘을 지원한다.

· 파이썬의 클래스 메커니즘은 새로운 구문과 의미론적 측면에서 C++의 구조를 바탕으로 만들어졌다. 

· 파이썬은 변수, 함수 등이 모두 객체로 구성되어 있으며 대부분의 내장된 특수 구문, 연산자, 클래스 객체에 대한 재정의를 할 수 있다.

 

클래스의 형식과 선언

· 클래스 선언 형식:

class 클래스명<(상속 클래스명...)>:
    멤버변수 = 값    # 클래스 변수
    ...
    def __init__(self): # 생성자
        ...
    def 메서드명(self): # 메서드
        ...

 

클래스를 선언하면,

- 새로운 이름공간(클래스가 만들어지는 기억 공간)을 생성하는 자료형 객체가 된다.

-  메서드와 멤버변수(attribute, 멤버필드)를 가질 수 있다.

- 클래스 간의 포함관계를 처리할 수 있다.

- 클래스 간의 상속관계를 처리할 수 있다.

 

· 예시

class Car:
    handle = 1

    def play(self):
        pass
    
    
# Car 클래스의 객체 생성
myCar = Car()

 

- 한 개의 클래스는 무수히 많은 객체를 만들 수 있다.

- Car() 명령문에 의해 메모리 어딘가에 Car 클래스 타입의 객체가 만들어지고 그 객체 고유 공간의 주소를 myCar라는 객체주소 참조변수(이하 객체변수)가 기억하게 된다.

 

생성자, 소멸자

· 파이썬은 생성자(constructor)와 소멸자(destructor)라는 메서드를 사용할 수 있도록 내부적으로 구현되어 있다.

· 생성자와 소멸자 메서드를 생략하면, 객체가 만들어질 때 내부적으로 내용이 없는 생성자와 소멸자가 만들어진다.

 

· 생성자는 __init__(self)라는 이름으로 제공되며, 클래스 객체가 생성될 때 자동으로 수행된다.

- 사용 목적: 객체 생성 시에 멤버변수를 초기화하거나 객체의 초기 상태를 위한 명령문을 실행하는 등의 초기화를 담당한다.

 

· 소멸자는 __del__(self)라는 이름으로 제공되며, 클래스 객체 수행이 완료되면 자동으로 수행된다.

- 사용 목적: 메모리에 저장된 자원 해제 등의 마무리 작업을 할 수 있다.

- 가비지컬렉터가 메모리 관리를 자동으로 해주므로 소멸자의 사용 빈도는 높지 않다.

 

· 예시1​

class Nice:
    name = ''   # 멤버변수 name 선언
    def __init__(self, name):   # 생성자이며 self 이외의 매개변수를 가질 수 있다.
        self.name = name    # Nice 클래스 타입 객체의 멤버인 name에 값 치환
        print('생성자 메서드에 의해 ' + name + '객체가 생성')
    def __del__(self):  # 소멸자이며 객체 처리가 완료되면 자동 수행
        del self.name   # name 변수의 역할을 해제

obj = Nice('tom')   # 객체 생성
print(obj)

결과

- 파이썬은 함수와 달리 생성자와 모든 메서드에 반드시 첫 번째로 적는 매개변수로 self가 있다.

- 메서드를 호출할 때 반드시 객체변수를 인수로 self 매개변수에 전달해야 한다. 그래야 해당 메서드가 클래스 타입의 객체별 고유 메서드로 인식된다.

- 위 예시에서 Nice 클래스의 생성자를 호출하면 매개변수에 객체변수 obj와 'tom'이라는 인수를 넘겨준다. 그러면 생성자 매개변수의 self에는 obj가 기억하고 있는 객체의 주소가, name에는 'tom'이 차례대로 기억된다.

 

· 예시2 - 두 가지 형태의 클래스 내부 멤버변수

- 클래스 내의 멤버변수는 정적변수(전역변수, 특정 클래스 타입으로 생성된 모든 객체가 공유)일반 멤버변수(각각의 객체에서만 공유)가 있다.

class Dog:
    kind = 'canine' # 클래스 멤버변수는 Dog 타입 클래스 객체의 어디에서나 공유 가능
    def __init__(self, name):
        self.name = name    # Dog 타입으로 생성된 각 고유 객체에서만 유효한 지역변수

dog1 = Dog('shepherd')
dog2 = Dog('SiberianHusky')

# kind는 클래스 멤버변수이므로 Dog 타입의 모든 객체에서 사용 가능
print(dog1.kind)
print(dog2.kind)

# name은 Dog 타입의 각 객체에서 독립적으로 사용
print(dog1.name)
print(dog2.name)

결과

 

클래스 다이어그램

· 클래스 다이어그램은 클래스의 구성 요소 및 클래스 간의 관계를 표현하는 통합 모델링 언어(UML, Unified Modeling Language)로 표현할 수 있는 다이어그램 중 하나다.

 

· 사용 목적: 시스템의 일부 또는 전체 구조를 나태내거나, 클래스의 멤버 관계를 도식화하여 명확히 보여줄 수 있어 소프트웨어의 설계 혹은 완성된 소프트웨어의 구현을 설명하기 위한 목적으로 많이 사용한다.

 

클래스로 새로운 타입 작성하기

· 예시1

class TestClass:
    num = 1  # 클래스 멤버변수는 클래스 객체에서 공유 가능

    def __init__(self): # 생성자의 매개변수로 반드시 self 주기
        print('생성자')

    def __del__(self):  # 소멸자의 매개변수로 반드시 self 주기
        pass    # 프로그램이 종료될 때 마무리 작업이 있으면 적기

    def printMessage(self): # 메서드의 매개변수도 self 주기
        name = '한국인'    # 메서드에서만 유효한 지역변수
        print(name, ' ', self.num)  # 클래스 멤버변수 호출 후 출력

print(TestClass.num)    # 클래스명.멤버로 클래스 멤버변수 참조 가능

test = TestClass()  # 생성자를 호출하면 객체가 생성된다.
print(test.num) # 객체변수로 멤버변수 num을 참조 가능

# 메서드를 호출하는 방법
test.printMessage() # Bound Method Call
TestClass.printMessage(test)    # Unbound Method call
print('클래스 타입:', isinstance(test, TestClass))

결과

- 클래스의 생성자, 소멸자, 일반 메서드는 반드시 self 매개변수를 갖는다.

- 메서드 호출 방식은 묵시적으로 인자를 매개변수에 전달하는 Bound Method call 방식과 명시적으로 객체변수를 매개변수에 넘겨주는 Unbound Method call 방식이 있다.

 

 

· 예시2 - 클래스 객체의 이름 공간

- 모듈은 파일 단위로 이름공간을 구성하고, 클래스는 클래스 이름공간과 인스턴스 이름공간을 별도로 생성한다. 즉, 객체변수의 개수만큼 인스턴스 이름공간이 만들어진다.

 

다음 클래스 다이어그램을 바탕으로 Car 클래스를 작성한다.

class Car:
    handle = 0   # 멤버변수 선언
    speed = 0

    def __init__(self, name, speed):    # 생성자, 매개변수는 3개
        self.name = name    # 새로 생성된 car type 객체의 고유 변수에 값 기억
        self.speed = speed  # 새로 생성된 객체의 speed 변수의 값 기억

    def showData(self):
        km = '킬로미터' # 지역변수가 된다.
        msg = '속도:' + str(self.speed) + km
        return msg

car1 = Car('tom', 10)   # 생성자 호출로 객체 생성
print(car1.handle, car1.name, car1.speed)
car1.color = '검점'   # car1 객체에 color 변수 추가
print('car1.color', car1.color)

car2 = Car('james', 20) # 새로운 객체 생성
print(car2.handle, car2.name, car2.speed)

print(id(Car), id(car1), id(car2))  # 주소 확인: 주소가 서로 다름
print('car1', car1.showData())  # car1 객체의 메서드 호출
print('car2', car2.showData())  # car1과 car2의 speed가 다름
print()

car1.speed = 50 # car1 객체변수의 speed 값을 변경
print('car1', car1.showData())  # car1 객체의 변경된 speed 확인
print()

print('car1 속도:', car1.speed)   # car1의 변경된 speed 확인
print('car2 속도:', car2.speed)   # car2의 speed는 변화 없음

결과

- speed는 멤버변수로 선언되어 각 객체에서 공유가 가능하다. 하지만 생성자에서 self.speed = speed로 self 매개변수의 특성으로 인해 각 객체에서 따로 관리되는 객체 고유 변수로 성격이 변경된다.

 

- Car 클래스를 선언하고, car1과 car2라는 두 개의 객체변수를 선언한다. 

- 각 객체변수에서 선언한 멤버는 해당 이름공간에서만 유효하다.

- 각 객체변수에서 원형 클래스와 이름이 같은 멤버를 변경하면 역시 해당 이름공간에서만 유효하다.

- 객체변수.멤버는 먼저 해당 객체변수의 이름공간에서 멤버를 찾고, 없으면 원형 클래스의 이름공간을 참조하게 된다.

- 클래스 정보는 내부적으로 __dict__라는 이름의 딕셔너리 자료형 객체로 관리된다.

  ▶ 위 소스에서 선언된 car1 객체변수가 참조하고 있는 이름공간의 멤버들을 확인하고 싶다면 car1.__dict__라는 명령을 실행하면 된다.

 

 

 

· 예시3 - 클래스 내에서 변수를 찾는 순서

- 다음 예시를 통해 변수의 생존 범위, 생존 시간, 참조 범위를 알아보자.

kor = 100   # 모듈 수준의 전역변수 kor은 100을 기억

def abc():  # 모듈 수준의 함수를 선언
    print("함수!")

class My:
    kor = 90    # My 클래스 내에서만 의미 있는 멤버변수

    def abc(self):  # My 클래스의 메서드
        print('메서드!')

    def show(self): # My 클래스의 메서드
        # kor = 88  -> show 메서드에서만 유효한 지역변수
        print(self.kor) # My 클래스 객체의 멤버변수 참조
        print(kor)  # 지역변수를 찾고, 없으면 모듈의 변수를 참조
        self.abc()  # My 클래스 객체의 메서드를 호출
        abc() # 모듈의 함수를 호출

obj = My()
obj.show()

결과

 

- 변수의 참조 순서는 '메서드 지역변수 > 객체변수 > 모듈변수' 순으로 우선순위가 높다.

 

클래스의 포함관계


· 기존에 만들어진 클래스의 코드를 다른 클래스에서 불러다 사용하도록 만들면 중복된 코드를 만들지 않고 사용할 수 있어서 동일한 코드에 대한 반복된 기록을 최소화할 수 있다. 이때,  다른 클래스를 호출해서 사용하는 기술은 크게 두 가지로 나뉜다.

 

관계 설명
포함(has a) · 특정 클래스 내에서 해당 클래스의 멤버처럼 다른 클래스 타입의 객체를 선언해 사용하는 것을 말한다.
· 이런 관계를 클래스와 클래스 간의 관계가 느슨한 약결합 관계다라고 말한다.
ex) 엔진, 핸들, 타이어 등이 자동차를 구성한다.
상속(is a) · 특정 클래스 타입의 객체가 다른 클래스 객체에게 자신의 멤버를 사용할 수 있도록 해 주는 것을 말한다. 유형이 같은 클래스 간의 관계를 맺는 것으로 부모자식 관계가 만들어진다.
· 이런 관계를 클래스와 클래스 간의 관계가 밀접하게 연결된 강결합 관계다라고 말한다.
ex) 개와 고양이는 둘다 동물이다.

 

· 예시

- 핸들은 자동차, 저건거, 오토바이 등 방향 전환을 위한 제품에서 모두 필요하다. 그래서 별도의 핸들을 만들어 두고, 핸들이 필요한 각 제품을 만들 때 부품으로 사용하면 작업이 간편해진다.

- Handle 클래스와 Car 클래스를 만든 후 두 개의 클래스를 서로 다른 파일로 저장한다. Car 클래스는 Handle 클래스를 포함하여 완성하고, Car 클래스가 완성되면 운전자가 운전을 하며 핸들을 움직인다.

 

Car와 Handle 클래스의 관계는 다음과 같다.

Car 클래스와 Handle 클래스의 관계

예시에 사용되는 패키지와 모듈 구성은 다음과 같다.

 

Handle.py

class Handle:
    quantity = 0  # 회전량을 기억

    def leftTurn(self, quantity):  # 좌회전일 때 수행
        self.quantity = quantity
        return '좌회전'

    def rightTurn(self, quantity):  # 우회전일 때 수행
        self.quantity = quantity
        return '우회전'

 

Car.py

from 클래스.Handle import Handle


class Car:
    turnShow = '정지'

    def __init__(self, ownerName):
        self.ownerName = ownerName  # 객체별로 ownerName 멤버를 기억
        self.handle = Handle()  # 클래스의 포함관계가 된다.

    def turnHandle(self, q):  # q 값으로 회전 방향을 결정
        if q > 0:
            self.turnShow = self.handle.rightTurn(q)
        elif q < 0:
            self.turnShow = self.handle.leftTurn(q)
        elif q == 0:
            self.turnShow = '직진'

 

Driver.py

from 클래스.Car import Car

tom = Car('ted')
tom.turnHandle(10)  # tom이 우회전
print(tom.ownerName + '의 회전량:' + tom.turnShow + str(tom.handle.quantity))

robin = Car('robin')
robin.turnHandle(-25)  # robin이 우회전
print(robin.ownerName + '의 회전량:' + robin.turnShow + str(robin.handle.quantity))

 

코드 작성이 완료되면, Driver.py 모듈을 실행한다.

결과

 

클래스의 상속관계


· 객체 간의 관계를 구현하는 방법 중 하나로, 자원의 재활용을 목적으로 한다는 점은 포함관계와 같으나 구현 방법은 다르다.

 

· 사용법: 여러 클래스가 공통적으로 필요로 하는 멤버를 가진 상위 클래스를 만든다. 이 클래스를 수퍼 클래스, 부모클래스 등으로 부른다. 부모크랠스를 만든 다음 부모클래스가 만든 멤버를 필요로 하는 하위 클래스를 만드는데, 이 하위 클래스는 부모크랠스로부터 속석과 동작을 상속 받는다. 이러한 클래스를 서브클래스 또는 자식 클래스라고 한다.

class 클래스(부모클래스):
	...

 

· 상속을 통한 클래스들의 관계는 자연스럽게 계층을 형성한다.

· 부모클래스의 멤버는 자식클래스에게 자동으로 지원된다.

· 파이썬이 제공하는 Object 클래스는 모든 클래스의 최상위 수퍼클래스가 된다.

 

· 상속관계의 장점: 상속을 통해 상위 클래스의 멤버를 여러 하위 클래스가 재사용할 수 있어

1. 소스의 재활용에 효과적이고,

2. 분업화가 가능하며,

3. 프로그램 유지보수가 간편해져 개발 비용을 절감할 수 있다.

 

· 예시1

- 동물의 공통적인 특성 및 행위를 멤버로 선언한 Animal 클래스를 만들고, 여러 동물 클래스가 Animal 클래스를 상속 받도록 한다.

class Animal:  # 부모클래스
    def move(self):
        print('움직이는 생물')


class Dog(Animal):  # Animal 클래스를 상속
    def my(self):  # Dog 클래스의 고유 메서드
        print('강아지')


class Horse(Animal):  # Animal 클래스를 상속
    pass  # Horse는 자체 멤버가 없는 클래스가 된다.


dog = Dog()
dog.my()  # Dog의 고유 메서드 수행
dog.move()  # Dog의 부모인 Animal의 메서드를 수행

horse = Horse()
horse.move()  # Horse의 부모인 Animal의 메서드를 수행

결과

- dog.my()하면 Dog 객체에서 my라는 메서드를 찾아 수행한다. dog.move()하면 먼저 Dog 객체에서 move 메서드를 찾아 수행하고, 해당 메서드가 없다면 부모클래스인 Animal 클래스의 영역으로 이동하여 move 메서드를 찾아 수행한다.

 

※ 멤버의 참조 순서는 자식클래스에서 부모 클래스 순이며, 지역이 전역보다 우선순위가 높다.

 

· 예시2

- 사람이 공통적으로 가질 수 있는 멤버를 가진 부모클래스 Person을 만들고, 자식클래스로 Employee와 Worker 클래스를 선언한다. Worker는 다시 하위 클래스로 Programmer 클래스를 갖는다. 

 

 

 

- 클래스의 멤버를 참조할 때 부모클래스와 자식클래스에 동일한 이름의 멤버가 있다면, 자식클래스의 멤버가 참조된다.

- 자식 클래스에서 똑같은 이름의 부모와 자식의 멤버를 참조하려 할 때는 자식은 'self.멤버'하면 되고, 부모의 멤버를 직접 호출할 때는'super().멤버'라고 하면 된다.

 

class Person:
    say = '사람사람'  # 클래스 멤버변수
    age = 20

    def __init__(self, age):  # 생성자 매개변수로 age를 받아 각 객체에 고유한 age를 갖는다.
        print('Person 생성자')
        self.age = age

    def printInfo(self):  # self에 전달되는 객체 주소에 따라 say와 age 값으이 결정
        print('say:{}, age:{}'.format(self.say, self.age))


class Employee(Person):
    say = '일하는 사람'  # 부모와 같은 이름의 멤버변수에 부모와 다른 값이 기억
    subject = '근로자'  # Employee만의 고유 멤버변수로 사용

    def __init__(self):
        print('Employee 생성자')

    def eprintInfo(self):
        self.printInfo()  # 현재 클래스의 메서드를 참조, 없으면 부모 메서드 참조
        super().printInfo()  # super()에 의해 바로 부모 메서드를 참조
        print(self.say)  # 현재 클래스에서 say를 참조하고, 없으면 부모의 say를 참조
        print(super().say)  # super()에 의해 바로 부모의 say를 참조

    def printInfo(self):
        print('오버라이딩(override): 부모와 같은 이름의 메서드를 자식에서도 선언')


class Worker(Person):
    def __init__(self, age):
        print('Worker 생성자')
        super().__init__(age)  # Worker의 부모클래스 생성자를 호출, age를 인수로 전달

    def wprintInfo(self):
        self.printInfo()


class Programmer(Worker):  # Worker의 자식클래스
    def __init__(self, age):
        print('Programmer 생성자')
        # super().__init__(age)     # Bound call 방식으로 부모클래스 생성자 호출
        Worker.__init__(self, age)  # UnBound call 방식으로 부모클래스 생성자 호출

    def pprintInfo(self):
        self.printInfo()  # printInfo()를 Programmer -> Worker -> Person 순으로 찾는다.
        super().printInfo()  # printInfo()를 Worker -> Person 순으로 찾는다.


person = Person('22')  # Person 객체 생성
person.printInfo()  # Person 클래스의 메서드를 호출
print()

empl = Employee()  # Employee 객체 생성
print(empl.say, empl.age, empl.subject)
empl.eprintInfo()
print()

worker = Worker('31')  # Worker 객체 생성
print(worker.say, worker.age)
worker.wprintInfo()
print()

pr = Programmer(33)  # Programmer 객체 생성
print(pr.say, pr.age)

결과

- 메서드 오버라이드란 부모클래스로부터 상속받은 메서드를 자식클래스에서 재정의하여 사용하는 것이다.

 사용 목적: 부모클래스에서 정의된 메서드를 자식클래스에서 부모와 다른 기능으로 정의해서 사용하고자 할 때 사용한다.

 

위 예시에 더불어 알아두면 좋은 내용

# 클래스 타입 확인하기
print(type(pr))

# 부모클래스의 이름을 확인하기
print(Programmer.__base__)
print(Worker.__base__)
print(Person.__base__)

# MRO(Method Resolution Order)로 메서드 결정 순서 확인하기. 먼저 출력된 값일수록 실행 우선순위가 높다.
print(Programmer.__mro__)

결과

 

다중 상속의 이해와 구현

· 파이썬은 다중 상속을 지원한다. 즉, 하나의 자식클래스에 부모클래스가 여러 개 있을 수 있다.

· 사용법:

class 자식클래스(부모클래스1, 부모클래스2,...)
	...

 

· 예시

class Donkey:
    data = "당나귀 최고"

    def skill(self):
        print("당나귀: 짐나르기")

class Horse:
    def skill(self):
        print("말: 달리기")

    def hobby(self):
        print("말은 달리기가 취기")


class Mule1(Donkey, Horse):   # Donkey, Horse 순으로 다중 상속
    pass


class Mule2(Horse, Donkey): # Horse, Donkey 순으로 다중 상속
    def play(self):
        print("노새 고유 메서드")

    def hobby(self):    # 부모 메서드를 오버라이드
        print("노새는 걷기를 즐김")

    def showHobby(self):
        self.hobby()    # 클래스의 멤버 호출은 self
        super().hobby() # 부모 멤버 호출 시 super()

    def showData(self):
        print(self.data)    # 클래스 자신의 멤버부터 호출
        print(super().data) # 부모 멤버를 호출

mu1 = Mule1()
print(mu1.data) # Donkey의 멤버변수를 참조
mu1.skill()     # Donkey의 메서드를 수행
mu1.hobby()     # Horse의 메서드를 수행
print()

mu2 = Mule2()
mu2.skill()     # Horse의 메서드를 수행
mu2.hobby()     # Mule2의 메서드를 수행
mu2.play()      # Mule2의 메서드를 수행
mu2.showHobby()
mu2.showData()

결과

- 다중 상속은 상속 순서가 중요하다. 먼저 적어준 부모클래스에 대한 멤버 참조의 우선순위가 높다.

 

멤버 참조 방법 차이점
self.멤버 현재 클래스의 멤버(변수 또는 메서드)를 찾고 없으면 부모클래스의 멤버를 찾는다.
super().멤버 현재 클래스의 멤버(변수 또는 메서드)는 무시하고 바로 부모클래스의 멤버를 찾는다.

 

추상클래스의 이해와 구현

· 추상메서드란 메서드의 이름은 있으나 수행할 내용이 없으며, @abstractmethod로 장식된 메서드를 말한다.

· 추상메서드를 하나라도 가지고 있는 클래스를 추상클래스라고 부른다.

· 추상클래스를 상속받은 자식클래스는 추상클래스에 존재하는 추상메서드를 필수적으로 오버라이딩하도록 강제된다. 그렇지 않으면 생성이 불가능 하다.

생성시 다음 오류 발생

· 추상클래스는 자체적으로 객체를 생성할 수 없다. 그래서 부모의 역할로만 의미를 갖는다.

· 추상 클래스는 추상메서드가 없어도 가능하지만, 보통 추상메서드가 있는 것이 상식이다.

 

· 추상메서드의 사용 목적:

1. 프로그램을 작성할 때 여러 클래스에서 공통으로 사용될 메서드의 이름을 똑같이 만들도록 강요함으로써 프로그램의 일관성을 유지할 수 있다.

2. 하위 클래스를 작성할 때 가이드라인을 제공해준다.

 

· 예시

- abcMehod라는 추상메서드를 갖고 있는 추상클래스인 AbstractClass와 이를 상속하는 자식클래스를 작성한다.

from abc import *

class AbstractClass(metaclass=ABCMeta):  # 추상클래스
    @abstractmethod
    def abcMethod(self):    # 추상메서드
        pass

    def normalMethod(self):    # 일반메서드
        print('추상클래스 내의 일반 메서드')


class Child1(AbstractClass):    # 추상클래스를 상속
    name = '난 Child1'

    def abcMethod(self):    # 메서드 선언을 강요
        print('추상메서드를 오버라이드함')


class Child2(AbstractClass):    # 추상클래스를 상속
    def abcMethod(self):    # 메서드 선언을 강요
        print('추상메서드를 Child2d에서 오버라이드함')

    def normalMethod(self): # 일반 메서드 오버라이드는 선택적
        print('추상클래스의 일반 메서드를 재정의')


c1 = Child1()   # Child1 객체 생성
print(c1.name)
c1.abcMethod()
c1.normalMethod()
print()

c2 = Child2    # Child2 객체 생성
c2.abcMethod(c2)
c2.normalMethod(c2)

결과

- 추상클래스를 사용하려면, 먼저 from abc import *와 같이 라이브러이 내의 모듈을 import해야 한다.

- 추상클래스는 자식클래스명()의 괄호 안에 class AbstracClass(metaclass=ABCMeta):처럼 적어 주면 된다.

▶ ABCMeta를 상속받은 클래스는 추상클래스가 된다.

반응형

댓글