상속 클래스
- 구현된 클래스의 기능(메소드)을 그대로 가져다가 사용하거나 아니면 그 기능 수정하거나 아니면 추가하거나 할 때 사용하는 개념
- 부모클래스의 속성(인스턴스 변수와 메소드)들을 자식클래스가 그대로 물려받는 개념
- 확장 개념, 부모클래스와 자식클래스가 합쳐지는 개념
1) 부모클래스 정의
class PlayerCharacter:
def __init__(self,hp=100,exp=0):
self.hp = hp
self.exp = exp
def attack(self):
print("공격하기")
self.exp += 2
def defend(self):
print("방어하기")
self.exp += 1
2) 자식클래스 선언
class Wizard(PlayerCharacter): # 부모 클래스 넣어 주기
def __init__(self,mp):
self.mp = mp
super().__init__() # 부모클래스의 생성자를 실행하겠다.
def magic_skill(self):
print("마법 공격하기")
self.mp = self.mp - 2
상속 클래스의 부모 클래스는 일반 클래스와 동일하나 자식 클래스는 클래스를 선언하고, 자식 클래스를 넣어줘야 한다.
그리고 super( ).__init__( )을 사용하면 부모클래스의 생성자를 이용하겠다는 뜻이다.
그래서 부모클래스의 생성자를 쓰려면 항상 있어야한다.
3) 실행
player = Wizard(10)
player.attack()
=> 공격하기
증명
class PlayerCharacter:
def __init__(self,hp=100,exp=0):
print(f"부모의 주소값: {id(self)}") # 에러 시 사용하여 확인
self.hp = hp
self.exp = exp
def attack(self):
print("공격하기")
self.exp += 2
def defend(self):
print("방어하기")
self.exp += 1
class Wizard(PlayerCharacter): # 부모 클래스 넣어 주기
def __init__(self,mp):
self.mp = mp
super().__init__() # 부모클래스의 생성자를 실행하겠다.
print(f"자식의 주소값: {id(self)}")
def magic_skill(self):
print("마법 공격하기")
self.mp = self.mp - 2
Wizard(30)
=> 부모의 주소값: 139938407770960
자식의 주소값: 139938407770960
<__main__.Wizard at 0x7f45f315eb50>
다음과 같이 상속 클래스를 만들고, id를 이용하여 주소값을 출력하면 주소값이 같은 것을 알 수 있다.
오버라이딩 (Override)
- 부모로부터 받는 메소드를 수정하고 싶을 때 자식클래스에서 재정의한다.
- 다른 자식클래스를 만들어도 똑같이 적용된다.
예시
class PlayerCharacter:
def __init__(self,hp=100,exp=0):
self.hp = hp
self.exp = exp
def attack(self):
print("공격하기")
self.exp += 2
def defend(self):
print("방어하기")
self.exp += 1
class Wizard(PlayerCharacter): # 부모 클래스 넣어 주기
def __init__(self,mp):
self.mp = mp
super().__init__() # 부모클래스의 생성자를 실행하겠다.
def magic_skill(self):
print("마법 공격하기")
self.mp = self.mp - 2
def defend(self): # 메소드 오버라이딩!
print("마법사가 방어하기")
self.exp += 3
player = Wizard(10)
player.defend()
=> 마법사가 방어하기
위와 같이 처음 defend는 부모 클래스에서 선언이 되었지만 자식 클래스에서 defend를 수정하여 출력할 수 있다.
여기서 다른 자식 클래스 만들어 선언해도 수정값은 변경되지 않는다.
non public (private)
- private: 인스턴스 변수나 메소드를 클래스 내부에서만 사용하게 하는 것
- 바깥에서 사용이 불가능하도록 하는 설정
- 맹글링(mangling) 기법을 이용해서 외부에서 직접적으로 인스턴스 변수나 메소드에 접근하는 것을 막을 수 있다.
예시
class Wizard(PlayerCharacter):
def __init__(self,mp):
super().__init__()
self.__mp = mp # 변수도 private
def __magic_skill(self): # private
print("마법 공격하기")
self.__mp -= 2
def magic_skill(self):
if self.__mp > 1:
self.__magic_skill()
else:
print("MP가 부족합니다.")
player = Wizard(50)
player.__magic_skill()
=> AttributeError Traceback (most recent call last)
<ipython-input-251-4ad15eaae4fe> in <module>()
1 player = Wizard(50)
----> 2 player.__magic_skill()
AttributeError: 'Wizard' object has no attribute '__magic_skill'
private는 간단하게 접근을 막고 싶은 메소드 앞에 "__" 을 붙여 넣으면 된다.
그래서 위 코드를 보면 "__magic_skill"를 써서 private 하게 만들어 주었기 때문에 접근할 때 에러가 나타나게 된다.
매직 메소드
- 메소드 명이 두개의 언더바로 감싸져있다.
- 파이썬의 다양한 내장함수들이 클래스의 매직메소드들을 호출하여 결과를 만들어 낸다.
- call, str, len, getitem 이 있다.
예시
class MyDataset:
def __init__(self,data):
self.data = data
def __call__(self,a):
print(f"{a} 함수 호출 방법처럼 객체를 함수 호출하듯이 만들어 주는 메소드")
def __str__(self): # print 함수에 이 클래스의 객체를 넣을 경우, 이 메소드에 리턴값을 출력해준다.
return "My dataset Class"
def __len__(self): # len() 내장함수는 객체의 이 매직메소드를 호출!
return len(self.data)
def __getitem__(self,idx): # 인덱싱과 슬라이싱을 가능하게 한다.
return self.data[idx]
1) 50 ~ 99까지의 리스트를 만들었다.
이것들을 매직 메소드에 적용시켜보겠다.
data = list(range(50,100))
dt = MyDataset(data)
dt
2) 실행
dt(1004) # __call__
=> 1004 함수 호출 방법처럼 객체를 함수 호출하듯이 만들어 주는 메소드
------------------------------------------------------------------
print(dt) # __str__
=> My dataset Class
------------------------------------------------------------------
len(dt) # __len__
=> 50
------------------------------------------------------------------
dt[:0] # get_item # __getitem__
=> 50
------------------------------------------------------------------
위와 같이 매직 함수를 이용함으로써 코딩의 질을 높일 수 있다.
getter&setter (참고용)
- 인스턴스 변수에 접근할 때 특정 로직을 거쳐서 접근시키는 방법
- getter & setter 정의할 인스턴스 변수는 private화 하자.
class Wizard(PlayerCharacter):
def __init__(self,mp):
super().__init__()
self.mp = mp
@property # getter 세팅할 때는 다음과 같이 데코 넣기
def mp(self):
print("getter 동작")
return self.__mp
@mp.setter # setter 세팅할 때는 getter의 메소드명.setter 데코
def mp(self,mp):
print("setter 동작")
if mp < 0:
mp = 0
self.__mp = mp
getter랑 setter는 그냥 이런 것이 있구나 한번 이해하고, 지나가면 된다고 해서 그리 깊게 보진 않았다.
오늘도 문제를 많이 풀었는데 많이 부족하다는 걸 느낀다.
문제를 푸는 것이 제일 힘들고, 하기 싫지만 이것만큼 실력이 많이느는 것이 없는 것 같다.
하기 싫다는 생각이 들땐 이것 또한 자의식의 방해라 생각하고, 열심히 해야겠다!
'AI 공부 > 파이썬' 카테고리의 다른 글
파이썬 (모듈과 패키지, sys, os, random 모듈) (0) | 2022.08.08 |
---|---|
파이썬 (50 문제 풀고, 부족한 개념 정리) (0) | 2022.08.06 |
파이썬 (클래스 - 1) (0) | 2022.08.03 |
파이썬 (함수 - 2) 람다함수, 콜백함수, map함수, Closure, Decorator (0) | 2022.08.02 |
파이썬 (함수 - 1) Argument 와 parameter, 깊은 복사, 얕은 복사 (0) | 2022.08.01 |
댓글