메소드 오버라이딩, 오버로딩
자바를 배웠다면 한번쯤은 들어봤을 단어이다. 객체 지향언어에서 특히 많이 사용된다.
개인적으로 이름이 비슷해서 너무 헷갈렸던 개념이었는데, 확실히 정리가 되었다.
- 오버라이딩은 부모 클래스의 메소드를 자식 클래스에서 재정의,
오버로딩은 오버라이딩과 비슷하지만 메소드 파라미터 기반 호출 방식
1. 서브 클래스 (자식) 에서 슈퍼 (부모) 클래스를 호출 후 사용 가능
2. 메소드 재정의 후 사용 가능
3. 부모 클래스의 메소드를 추상화 후 사용가능
- 재정의와 비슷하지만 구조적 접근이 가능하다.
4. 확장 가능, 다형성이 존재
- 다형성? 다양한 방식으로 동작한다는 의미다.
부모에서 하나를 만들어도 자식에서 어떻게 정의하느냐에 따라 달라진다.5. 가독성 증가, 오류 가능성 감소
- 개발은 나 혼자 개발하는 거 아니다.
오버라이딩을 통해 유지보수 쉬워진다.6. 메소드 이름 절약
- 코딩을 하다 보면 메소드 동작에 맞지 않는 네이밍을 할 때가 있다.
게다가 똑같은 기능을 하는 메소드인데 이름을 이상하게 짓게 되기도 한다.- 부모 클래스에서 메소드의 이름을 정의해놓고, 자식 클래스에서 상속 받아서 하나의 메소드의 이름으로 사용이 가능하다.
a
를 상속 받기 위해선, 클래스를 선언할 때 인자로 함께 넣어주면 된다. b(a)
class ParentEx1():
def __init__(self):
self.value = 5
def get_value(self): #내부 인스턴스 value를 반환하는 함수
return self.value
# 부모 클래스를 상속 받음
class ChildEx1(ParentEx1):
pass
c1 = ChildEx1()
p1 = ParentEx1()
# 부모 클래스 메소드 호출
# 자식 클래스엔 정의가 안된 함수로 값을 출력 가능하다.
print("ex 1 > ",c1.get_value())
# c1의 모든 속성 출력
print("ex 1 > ",dir(c1))
# [ ... , 'get_value', 'value']
# 부모와 자식의 모든 속성 출력
# print('ex 1 >', dir(ParentEx1))
# print('ex 1 >', dir(ChildEx1))
그렇다면 클래스.__dict__
로 네임스페이스를 확인해보자 ⭐️
name space
name들의 공간으로, 변수 이름과 객체가 연결된 공간을 떠올리면 된다.
# 부모와 자식의 네임스페이스 확인 ( 중요 )
print('ex 1 >', ParentEx1.__dict__)
print('ex 1 >', ChildEx1.__dict__)
# ---- 출력 ----
ex 1 > Parent.__dict__ :
{'__module__': '__main__', '__init__':
<function ParentEx1.__init__ at 0x7fdfa9299700>,
'get_value': <function ParentEx1.get_value at 0x7fdfa92514c0>,
'__dict__': <attribute '__dict__' of 'ParentEx1' objects>,
'__weakref__': <attribute '__weakref__' of 'ParentEx1' objects>, '__doc__': None}
ex 1 > Child.__dict__ :
{'__module__': '__main__', '__doc__': None}
class ParentEx2():
def __init__(self):
self.value = 5
def get_value(self):
return self.value
# 부모 클래스를 상속 받아서, 같은 함수 이름을 이용해 재정의한다.
class ChildEx2(ParentEx2):
def get_value(self):
# 부모 클래스의 인스턴스 값에 10을 곱해서 리턴한다.
return self.value * 10
# 자식 메소드 재정의 후 호출
c2 = ChildEx2()
print('ex 2 > ',c2.get_value())
import datetime
class Logger(object):
def log(self, msg):
print(msg)
# 상속 받음
class TimestampLogger(Logger):
def log(self,msg):
message = "{ts} {msg}".format(ts=datetime.datetime.now(), msg=msg)
super(TimestampLogger, self).log(message)
class DateLogger(Logger):
def log(self,msg):
message = "{ts} {msg}".format(ts=datetime.datetime.now().strftime('%Y-%m-%d'), msg=msg)
super(DateLogger, self).log(message)
부모 클래스에 있는 요소를 사용하기 위해선 super를 사용해야 한다.
1. FM 식으로 코딩하기
super(내 자신 클래스 이름, 클래스이자 자식의 인스턴스)
class TimestampLogger(Logger):
def log(self,msg):
message = "{ts} {msg}".format(ts=datetime.datetime.now(), msg=msg)
super(TimestampLogger, self).log(message)
# super 인자 : (내 자신 클래스 이름, 클래스이자 자식의 인스턴스)
2. 조금 더 편하게 코딩하기
class TimestampLogger(Logger):
def log(self,msg):
message = "{ts} {msg}".format(ts=datetime.datetime.now(), msg=msg)
super().log(message)
import datetime
class Logger(object):
def log(self, msg):
print(msg)
# 상속 1
class TimestampLogger(Logger):
def log(self,msg):
message = "{ts} {msg}".format(ts=datetime.datetime.now(), msg=msg)
super(TimestampLogger, self).log(message)
# 상속 2
class DateLogger(Logger):
def log(self,msg):
message = "{ts} {msg}".format(ts=datetime.datetime.now().strftime('%Y-%m-%d'), msg=msg)
super(DateLogger, self).log(message)
l = Logger()
t = TimestampLogger()
d = DateLogger()
l.log('Called loger.')
# 출력: Called loger.
t.log('Called timestamp loger.')
# 출력: 2021-03-21 16:02:41.588938 Called timestamp loger.
d.log('Called date loger.')
# 출력: 2021-03-21 Called date loger.
출처: 인프런 - 모두를 위한 파이썬 : 필수 문법 배우기 Feat. 오픈소스 패키지 배포 (Inflearn Original)