* 캡슐화 : __를 2개 붙이면 그 변수의 이름은 네임 맹글링이 된다. 네임 맹글링이 된 후 새 이름을 사용하면
외부로부터 그 변수에 접근할 수 있기때문에 접근을 완벽하게 막을 수 있는 것은 아니다.
→ getter / setter 메소드를 직접 정의하는 것이 아니라 @property 데코레이터를 사용하는 것이 좋다.
@property 메소드를 사용하면 마치 변수에 직접 접근하는 것 같은 방식으로 변수의 값을 읽을 수 있다.
( 실제로는 getter / setter 메소드가 실행되는 것임 )
[ 상속 ]
상속이란 두 클래스 사이에 부모 - 자식 관계를 설정하는 것이다.
ex) A는 B이다.
A는 자식 클래스이고 B는 부모 클래스이다. 자식 클래스는 부모 클래스의 모든 변수와 메소드를 물려받는다.
상속은 자식 클래스 이름 뒤에 괄호를 쓰고 괄호 안에 상속할 부모 클래스 이름을 적으면 된다.
class Employee: # 직원 클래스
company_name = "HELLO" # 회사 이름
raise_percentage = 1.03 # 시급 인상률
def __init__(self, name, wage):
self.name = name
self.wage = wage
def raise_pay(self):
self.wage *= self.raise_percentage
def __str__(self):
return Employee.company_name + " 직원 이름 : " + self.name
class Development_team(Employee): # 개발팀 직원
pass
class Design_team(Employee): # 디자인팀 직원
pass
p1 = Development_team("2chaechae", 3000)
p1.raise_pay()
print(p1) # HELLO 직원 이름 : 2chaechae
print(p1.wage) # 3090.0
Developement_team 클래스가 Employee 클래스를 상속받았기 때문에 물려받은 변수와 메소드를 사용할 수 있다.
* help 함수 : class의 정보를 자세히 출력
* 파이썬에서 모든 class는 자동으로 Builtins.object class를 상속받는다.
→ 파이썬에서 모든 class는 Builtins.object class의 자식 class이다.
상속과 관련된 메소드들
1. mro() : 해당 클래스가 상속하는 부모 클래스를 볼 수 있다.
* mro : Method Resolution Order → 메소드 검색 순서
print(Development_team.mro())
# [<class '__main__.Development_team'>, <class '__main__.Employee'>, <class 'object'>]
object 클래스는 Development_team 클래스의 입장에서 부모 클래스의 부모 클래스이다.
즉, object 클래스는 최상위 클래스이다.
2. isinstance( 검사할 인스턴스, 기준 클래스 ) : 검사할 인스턴스가 기준 클래스의 인스턴스인지 Boolean 값 출력
p1 = Design_team("2chaechae", 3000)
print( isinstance(p1, Development_team) ) # False
print( isinstance(p1, Design_team) ) # True
print( isinstance(p1, Employee) ) # True
상속 관계에 있는 두 클래스가 있을 때 자식 클래스로 만든 인스턴스는 부모 클래스의 인스턴스이기도 하다.
3. issubclass( 검사할 클래스, 기준이 되는 부모 클래스 ) : 검사할 클래스가 기준이 되는 부모 클래스의
자식 클래스인지 Boolean 값 출력
print(issubclass(Development_team, Employee)) # True
print(issubclass(Development_team, object)) # True
print(issubclass(Design_team, Employee)) # True
print(issubclass(Employee, list)) # False
Employee 클래스는 list 클래스와는 아무 상관이 없으므로 False이다.
오버라이딩
부모 클래스에서 물려받은 내용을 자식 클래스가 자신에 맞게 변경및 수정하는 것을 오버라이딩이라 한다.
오버라이딩은 자식 클래스에서 물려받은 메소드를 같은 이름의 메소드로 내용을 바꿔서 정의해주면 된다.
오버라이딩을 하면 자식 클래스로 인스턴스를 생성할 때 부모 클래스로부터 물려받은 메소드가 아니라 자식 클래스
자신의 메소드가 실행된다.
class Development_team(Employee): # 개발팀 직원
def __init__(self, name, wage, major):
Employee.__init__(self, name, wage) # 부모 클래스의 객체 사용
self.major = major
super()는 자식 클래스에서 부모 클래스의 메소드를 사용하고 싶을 경우 쓰는 함수이다.
super()로 부모 클래스의 메소드를 사용할 때는 self 파라미터를 넘겨줄 필요가 없다.
super().__init__(name, wage)
< __str__ 메소드 오버라이딩 하기 >
class Development_team(Employee): # 개발팀 직원
def __init__(self, name, wage, major):
super().__init__(name, wage) # 부모 클래스의 객체 사용
self.major = major
def __str__(self):
return Development_team.company_name + " 개발팀 직원 : " + self.name
p1 = Development_team("2chaechae", 3000, "Computer")
print(p1) # HELLO 개발팀 직원 : 2chaechae
< 변수 오버라이딩 하기 → 자식 클래스에서 다른 값을 대입하기 >
변수를 오버라이딩 할 경우 자식 클래스에서 똑같은 이름의 변수를 두고 다른 값을 넣으면 된다.
class Development_team(Employee): # 개발팀 직원
raise_percentage = 1.05 # 변수 오버라이딩
def __init__(self, name, wage, major):
super().__init__(name, wage) # 부모 클래스의 객체 사용
self.major = major
def __str__(self): # __str__ 오버라이딩
return Development_team.company_name + " 개발팀 직원 : " + self.name
p1 = Development_team("2chaechae", 3000, "Computer")
p2 = Employee("2MONMON", 3100)
print(p1.raise_percentage) # 1.05
print(p2.raise_percentage) # 1.03
* mro() : 클래스가 상속받는 부모 클래스들이 순서대로 담긴 리스트를 리턴한다.
파이썬은 물려받은 메소드와 같은 이름의 메소드를 다시 정의해서 오버라이딩을 한다. 그러면 자식 클래스에는 물려
받은 메소드와 오버라이딩한 메소드 두 개가 모두 존재하는데 오버라이딩된 메소드를 출력할 수 있는 이유는
파이썬이 mro의 리턴값인 리스트에 나와있는 순서대로 메소드를 탐색하기 때문이다.
→ mro에서 앞에 나오는 자식 클래스의 메소드가 뒤에 나오는 부모 클래스의 같은 이름의 메소드보다 먼저 찾아져서
호출되는 것이다.
print(Development_team.mro())
# [<class '__main__.Development_team'>, <class '__main__.Employee'>, <class 'object'>]
mro는 메소드 검색 순서를 의미한다. mro의 출력 결과에 있는 순서대로 메소드는 자식 클래스부터 부모 클래스
방향으로 검색이 되는데 부모 클래스와 자식 클래스에 같은 이름의 메소드가 있더라도 자식 클래스의 메소드가
먼저 검색되서 실행되기 때문에 메소드 오버라이딩이 가능하다.
자식 클래스에 변수와 메소드 추가해보기
class Development_team(Employee): # 개발팀 직원
raise_percentage = 1.05
able_skill = list()
def __init__(self, name, wage, major):
super().__init__(name, wage) # 부모 클래스의 객체 사용
self.major = major
def improve_skill(self, add_skill):
if add_skill in self.able_skill :
print("이미 등록된 기술입니다.")
else :
self.able_skill.append(add_skill)
print("사용 가능한 기술이 추가되었습니다.")
def __str__(self):
return Development_team.company_name + " 개발팀 직원 : " + self.name
p1 = Development_team("2chaechae", 3000, "Computer")
p1.improve_skill("Python") # 사용 가능한 기술이 추가되었습니다.
print(p1.able_skill)
p1.improve_skill("Python") # 이미 등록된 기술입니다.
다중 상속
다중 상속 : 하나의 자식 클래스가 여러 부모 클래스를 상속받는 것이 가능하다.
ex) 복수 전공인 student 클래스 만들어보기
자식 클래스인 student 클래스는 부모 클래스인 major_law와 major_sw 클래스로 부터 변수와 메소드를 물려받는다.
class major_law:
def __init__(self, law_credit):
self.law_credit = law_credit
def check_law_credit(self):
print("법학 전공 이수 학점 : {}".format(self.law_credit))
if self.law_credit > 80 :
return "졸업 요건 : P"
else:
return "졸업 요건 : F"
class major_sw:
def __init__(self, sw_credit):
self.sw_credit = sw_credit
def check_sw_credit(self):
print("sw 전공 이수 학점 : {}".format(self.sw_credit))
if self.sw_credit > 100:
return "졸업 요건 : P"
else:
return "졸업 요건 : F"
class student(major_sw, major_law):
def __init__(self, law_credit, sw_credit):
major_sw.__init__(self, sw_credit)
major_law.__init__(self, law_credit)
# 다중 상속을 받는 클래스의 인스턴스 생성
chaechae = student(90, 80)
print(chaechae.check_sw_credit())
print(chaechae.check_law_credit())
# sw 전공 이수 학점 : 80
# 졸업 요건 : F
# 법학 전공 이수 학점 : 90
# 졸업 요건 : P
다중 상속의 경우 mro()를 호출하면 어느 클래스의 메소드가 호출될지 알 수 있다.
하지만 클래스를 여러 개 상속받을 경우 상속받는 순서에 따라 mro가 바뀐다.
< 다중 상속을 할 경우 >
파이썬에서 다중 상속을 하게 되면 해당 클래스의 mro는 상속을 받은 순서대로 설정된다.
1. 부모 클래스끼리 같은 이름의 메소드를 갖지 않도록 하는 것이 좋음
2. 다중 상속을 받아도 부모 클래스 간 중복되는 메소드를 자식 클래스에서 오버라이당하면
자식 클래스의 메소드가 우선 실행되서 애매모해지는 결과값을 예방할 수 있다.
3. 몇몇 객체 지향 언어들은 다중 상속을 허용하지 않음. ex) JAVA
'Python > 객체지향' 카테고리의 다른 글
[ 객체 지향 프로그래밍 ] 4일차 ( 추상화, 캡슐화 ) (0) | 2022.01.29 |
---|---|
[ 객체 지향 프로그래밍 ] 3일차 ( 객체 지향 언어 ) (0) | 2022.01.21 |
[ 객체 지향 프로그래밍 ] 2일차 ( __init__ ~ 클래스 메소드 ) (0) | 2022.01.20 |
[ 객체 지향 프로그래밍 ] 1일차 ( 객체지향 정의 ~ 인스턴스 ) (0) | 2022.01.12 |