상속 (inheritance)
두 클래스 사이 부모-자식 관계를 정립하는 것이다.
클래스를 상속받아 부모클래스가 가지는 특징(속성,메서드)을 재사용할 수 있다.
하위 클래슨느 상위클래스에 정의된 속성, 행동, 관계, 제약조건 모두 상속받는다.
모든 파이썬 클래스는 object를 조상클래스로 가지고 있기 때문에 object 클래스의 특징을 이용할 수 있다.
파이썬은 다중상속이 허용된다.
상속관계에서 이름 공간은 인스턴스, 자식 클래스, 부모 클래스 순으로 탐색한다.
class ChildClass(ParentClass):
pass
상속받고 싶은 부모클래스(super class)를 () 에 작성한다.
class Shape:
def __init__(self) :
self.name = '도형'
self.area = 0
def draw(self) :
print(f'{self.name}을 그린다.')
class Rectangle(Shape):
pass
Shape이라는 도형에 대한 속성을 가지는 클래스를 정의하고,
Rectangle 클래스를 생성해서 Shape을 상속받았다.
Rectangle 클래스에는 따로 지정한 속성이 없다.
rect1 = Rectangle()
rect1.area = 100
rect1.name = '사각형'
rect1.draw() #사각형을 그린다.
print(rect1.area, rect1.name) #100 사각형
Rectangle 클래스에는 아무런 속성, 메서드가 없지만 Shape 클래스를 속성받아 Shape 클래스가 가진 속성을 사용할 수 있다.
area, name 변수뿐만아니라 draw 메서드도 사용한다.
class Shape:
def __init__(self) :
self.name = '도형'
self.area = 0
def draw(self) :
print(f'{self.name}을 그린다.')
class Rectangle(Shape):
def __init__(self,width,height):
self.width=width
self.height=height
def cal_area(self):
self.area=self.width*self.height
class Circle(Shape):
pi=3.14
def __init__(self,radious):
self.radious=radious
def cal_area(self):
self.area=Circle.pi*self.radious**2
상속을 받는 이유는 공통된 속성을 가지고 세부적으로 다른 속성을 따로 지정해주기 위해서이다.
Shape 속성을 가지면서 사각형, 원의 속성을 따로 가지고 있는 클래스들을 각각 지정해주었다.
rect1 = Rectangle(20,20)
rect1.cal_area()
print(rect1.area) #400
c1 = Circle(5)
c1.cal_area()
print(c1.area) #78.5
각각의 클래스메서드를 이용했다.
rect1 = Rectangle(20,20)
print(rect1.name) #AttributeError: 'Rectangle' object has no attribute 'name'
__init__을 새로 지정했기 때문에 Shape의 생성자에서 설정되었던 name이 지정되지 않아 사용할 수 없다.
class Rectangle(Shape):
def __init__(self,width,height):
super().__init__()
self.width=width
self.height=height
def cal_area(self):
self.area=self.width*self.height
Rectangle 클래스의 생성자를 지정할 때 super().__init__()으로 부모클래스의 생성자를 호출해야 한다.
자식클래스 내에서 부모클래스를 지칭할 때 super 키워드를 사용한다.
부모클래스의 init메서드를 호출하는 것이다.
rect1 = Rectangle(20,20)
print(rect1.name) #도형
rect1.name = '사각형'
print(rect1.name) #사각형
따로 name을 지정해준적이 없기 때문에 부모클래스 생성자에 기본적으로 설정되었던 '도형' 이 출력된다.
인스턴스변수 name을 지정해주면 변경된다.
메서드 재정의 (method override)
상속을 통해 부모가 가진 메서드를 자식클래스에 맞게 변경해서 사용할 수 있다.
메서드 오버라이딩은 부모클래스에 정의된 메서드를 자식클래스에서 재정의하는 것이다.
부모클래스에 정의된 메서드랑 동일하게 만들면 된다.
class Rectangle(Shape):
def __init__(self,width,height):
super().__init__()
self.width=width
self.height=height
def cal_area(self):
self.area=self.width*self.height
def draw(self):
print('직선을 그립니다')
print('직선을 그립니다')
print('직선을 그립니다')
print('직선을 그립니다')
draw메서드를 재정의했다.
rect1.draw()
#직선을 그립니다
#직선을 그립니다
#직선을 그립니다
#직선을 그립니다
부모클래스에 있던 메서드 실행결과 (도형을 그립니다)가 아닌 재정의한 메서드가 실행된다.
class Circle(Shape):
pi=3.14
def __init__(self,radious):
self.radious=radious
def cal_area(self):
self.area=Circle.pi*self.radious**2
def draw(self):
print('곡선을 그립니다')
Circle에는 draw메서드를 또 다르게 지정했다.
(참고)
자바에서 메서드 오버로딩은 이름이 똑같은 메서드를 여러개 정의하는 것으로, 둘은 전혀 관계가 없다.
파이썬은 오버로딩이 되지 않는다.
오버로딩의 조건은 매개변수의 타입, 개수, 순서가 다른것인데 파이썬은 변수 타입 지정이 없기 때문에 오버로딩이 될 수 없다.
def func(arg1):
pass
def func(arg1,arg2):
pass
이런 경우에는 뒤에 작성된 함수가 위에 작성된 함수를 덮어씌우게 된다.
isinstance(객체, 클래스)
클래스의 객체인지 확인하는 메서드
클래스의 instance 이거나, subclass의 instance인 경우 True
class Person:
pass
class Student(Person):
pass
p=Person()
s=Student()
Person을 상속받은 Student를 만들고 각 객체를 생성했다.
print(isinstance(p,Person)) #True
print(isinstance(p,Student)) #False
print(isinstance(s,Person)) #True
print(isinstance(s,Student)) #True
상속받은 Student의 객체는 Student, Person의 객체로 확인된다. (True)
자식클래스는 부모클래스의 속성들을 가지고 오기 때문에 is a 관계라고 할 수 있다.
Student is a Person
자식클래스에 있는 속성이 부모클래스에는 없을 수 도 있기 때문에 반대의 경우는 다르다.
issubclass(클래스1, 클래스2)
클래스1이 클래스2의 subclass이면 True
print(issubclass(Student,Person)) #True
print(issubclass(Student,(Student,Person))) #True
super()
자식클래스에서 부모클래스를 지칭
다중상속
class W:
gene='여자'
class M:
gene='남자'
class Person(M,W):
pass
p=Person()
print(p.gene) #여자
class W:
gene='여자'
class M:
gene='남자'
class Person(M,W):
pass
p=Person()
print(p.gene) #남자
다중상속은 순서가 중요하다.
같은 변수가 있는 클래스들을 다중상속받을 때 앞에 적힌 것이 반영된다.
다형성
def draw_shape(shape) :
shape.draw()
draw를 실행하는 함수를 만들었다.
rect1 = Rectangle(20,20)
c1 = Circle(5)
draw_shape(rect1) #직선을 그립니다
draw_shape(c1) #곡선을 그립니다
각 객체를 생성했고, 함수를 실행한다.
같은 함수에서 인자만 바뀌었는데 실행하는 코드가 달라졌다.
같은 형태의 코드가 다른 동작을 하는 것을 다형성이라고 한다.
추상화
사용자로부터 프로세스 또는 메서드의 내부 구현을 숨긴다.
몰라도 되는 정보는 가리고 꼭 필요한 정보만 나타내는 것이다.
예를 들어 변수의 값을 알지 못하여도 변수는 사용할 수 있는 것이다.
클래스 내부에 선언된 변수나 메서드에 접근할 수 있는 권한을 줌으로써 허용된 범위에서만 접근이 가능하다.
캡슐화
객체의 일부 구현내용에 대해서 외부로부터의 직접적인 접근을 차단하는 것이다.
외부에서 내용의 내용을 알지못하게 한다.
파이썬에서는 암묵적으로는 존재하지만 언어적으로는 존재하지 않는다.
접근제어자
1. public member
일반적으로 사용되는 언더바 없는 메서드나 속성
어디서나 호출가능하고, 하위 클래스 override 허용된다.
2. protected member (암묵적인 약속)
언더바 1개로 시작하는 메서드나 속성
암묵적 규칙에 의해 부모클래스 내부와 자식클래스에서만 호출이 가능하다.
하위클래서 overrride 허용된다.
암묵적인 약속일뿐 오류는 발생하지 않는다.
3. private member
언더바 2개로 시작하는 메서드나 속성
본 클래스 내부에서만 사용가능하고, 하위클래스 상속 및 호출과 외부 호출은 불가능하다.
getter 메서드 / setter 메서드
변수에 접근할 수 있는 메서드를 별도로 생성해서 간접적으로 접근할 수 있다.
getter : 변수의 값을 읽는 메서드, @property 데코레이터 사용
setter : 변수의 값을 설정하는 메서드. @변수.setter 사용
class Person:
def __init__(self,age):
self.__age=age
p=Person(20)
print(p.__age) #AttributeError: 'Person' object has no attribute '__age'
__age는 private member로 외부에서 접근 불가능하기 때문에 오류가 발생한다.
class Person:
def __init__(self,age):
self.__age=age
@property
def age(self):
return self.__age
@age.setter
def age(self,new_age):
self.__age=new_age
p=Person(20)
#getter
print(p.age) #20
#setter
p.age=10
print(p.age) #10
__age 변수에 접근하기 위해서는 직접적으로 접근하지 않고,
getter, setter 메서드를 만들어서 변수에 간접적으로 접근해야 한다.
외부에서 보았을 땐 바로 변수에 접근하는 것 같지만, age라는 메서드를 실행한 것이다.
'Language > Python' 카테고리의 다른 글
자료구조 : 트리(tree), 이진탐색트리 파이썬으로 구현하기 (0) | 2022.09.16 |
---|---|
파이썬 - 클래스변수, 인스턴스변수, 클래스메서드, 인스턴스메서드, 스태틱메서드 (0) | 2022.07.28 |
파이썬 immutable / mutable (0) | 2022.07.27 |
딕셔너리 메서드 - get, setdefault, pop, update (0) | 2022.07.26 |
셋(set) 메서드 - add, update, remove, discard (0) | 2022.07.26 |