- 프롤로그
- 개발 첫걸음
- 파이썬 기초
- 파이썬 중급
- 파이썬 고급
- 내장 함수 톺아보기
- 예외와 에러 – 예상치 못한 상황에 대응하기 (v0.1)
- 변수의 범위 – 이름 검색의 범위
- 파이썬 심화
- 시퀀스와 반복자 – 반복과 순회를 자유자재로 다루기
- 데코레이터 – 함수의 기능을 강화하기
- 프로퍼티
- 제너레이터
- async와 await
- 객체로서의 클래스 – 클래스를 동적으로 정의하기
- 파이썬 프로젝트 실습
- 원카드 게임 만들기 (1)
- 원카드 게임 만들기 (2)
- 원카드 게임 만들기 (3) (작성중)
- 턴제 자동 전투 게임 만들기 (작성중)
- 실전 (파이썬 외적인 것들)
- 정규표현식 – 문자열을 검색하고 치환하기 (작성중)
- 유니코드 – 컴퓨터에서 문자를 표기하는 방법
- html, css, 인터넷 – 자동화 첫 걸음 내딛기
- 네트워크 – 인터넷으로 통신하는 방법
- 문서 – 문맥을 읽어보기
각종 에러를 접하다 보면 NotImplemented
와 NotImplement
가 혼동된다는 점을 알 수 있습니다. 여기서는 간단하게 그 차이만 알아보고, 자세한 사항은 연결고리를 참조합니다. 아래 두 주제 전부 클래스와 밀접한 연관이 있기 때문에 아직 클래스에 익숙하지 않다면, 클래스를 더 연습하고 오시기를 권장드립니다.
NotImplementedError
상위 클래스를 설계할 때, 하위 클래스에서 반드시 오버라이드하여 상세하게 구현해야 하는 메소드를 명시하고자 하려면, 해당 메소드의 내용으로 raise NotImplementedError(메시지)
만 넣어놓게 됩니다. 아래와 같이 BaseWheel
로 객체를 만들어놓고 roll
메소드를 호출하려고 하면 에러가 뜬다는 것을 확인할 수 있습니다.
class BaseWheel:
def roll(self):
raise NotImplementedError("roll 메소드를 구현하여야 합니다.")
class FastWheel(BaseWheel):
def roll(self):
print("빠르게 굴러간다~!")
someWheel = BaseWheel()
someWheel.roll()
Traceback (most recent call last):
File "c:/Users/tooth/Downloads/test.py", line 10, in <module>
someWheel.roll()
File "c:/Users/tooth/Downloads/test.py", line 3, in roll
raise NotImplementedError("roll 메소드를 구현하여야 합니다.")
NotImplementedError: roll 메소드를 구현하여야 합니다.
반면 FastWheel
로 roll을 호출하면 아무런 문제가 없다는 것을 알 수 있습니다.
class BaseWheel:
def roll(self):
raise NotImplementedError("roll 메소드를 구현하여야 합니다.")
class FastWheel(BaseWheel):
def roll(self):
print("빠르게 굴러간다~!")
someWheel = FastWheel()
someWheel.roll()
빠르게 굴러간다~!
에러는 다양한 경우에서 다른 개발자에게 의도를 보여주기 좋습니다. 만약 베이스 클래스를 만들면서 반드시 구현해야 하는 기능(메소드)를 명확하게 하기 위해 raise NotImplementedError(...)
를 활용하도록 합시다.
NotImplemented
어떤 클래스의 연산자, 특히 수치형에서 작동하는 중위 연산자에서 지원하지 않는 연산이라고 알리기 위해 NotImplemented
를 return
합니다.
NotImplemented
는 키워드이자 값입니다. 즉 None
이나 True
, False
와 동등한 지위를 가진 녀석이란 것이죠. True
가 참, False
가 거짓, None
이 아무 것도 없음을 나타내는 것처럼 NotImplemented
는 ㅁ구현되지 않음을 나타내는 것입니다.
수치 연산에서 굳이 에러를 발생시키지 않고 특정한 값을 반환하는 이유는, 파이썬 인터프리터가 다른 가능한 연산을 찾아볼 기회를 주기 위해서입니다. 보통 에러를 발생시킨다면 try-except 문에서 에러를 핸들링해주지 않는 이상 프로그램이 곧장 뻗습니다. 뭔가가 실패했을 때 다른 방법을 찾아보기보다 아무 것도 못하고 프로그램이 종료된다면, 설계가 유연해지지 않겠지요.
작동 원리는 다음과 같습니다. 어떤 클래스에서 __add__
메소드를 구현했는데 이 메소드 내부에서 NotImplemented
를 반환한다면, 파이썬은 __radd__
메소드를 검색해보는 시도 또한 해봅니다. 모든 시도가 NotImplemented
로 끝난다면, 그제서야 파이썬은 TypeError
를 발생시킵니다. 아래는 간단한 예시입니다.
class Time:
def __init__(self, hour, minute, second):
self.second = second
self.minute = minute
self.hour = hour
def __add__(self, other):
try:
return Time(self.hour, self.minute, other + self.second)
except TypeError:
return NotImplemented
def __repr__(self):
return f'Time(hour={self.hour}, minute={self.minute}, second={self.second})'
def __str__(self):
return f'{self.hour:0>2}:{self.minute:0>2}:{self.second:0>2}'
class Minute:
def __init__(self, value):
self.value = value
def __radd__(self, other):
return Time(other.hour, other.minute + self.value, other.second)
t = Time(12, 23, 00)
print("초기 상태", t)
t += 22
print("22초 추가", t)
m = Minute(15)
t += m
print("15분 추가", t)
Time
객체인 t
와 Minute
객체인 m
이 더해지는 t+m
연산에서, Time.__add__ 메소드는 TypeError
를 일으킵니다. 왜냐하면 Minute
가 int
와 더하는 연산을 지원하지 않기 때문이지요. 그래서 그 경우에는 NotImplemented
를 반환하도록 했습니다.
파이썬 인터프리터는 t+m
연산에서 NotImplemented
가 결과로 나왔으니, 이제 m의 클래스인 Minute
에서 __radd__
메소드를 찾습니다. 어, 있네요! 이것마저 안된다면 에러를 발생시킬 터였지만, 다행히 무사히 작동합니다. __radd__
에는 self
가 연산자 오른쪽에 있는 값이고, other
가 연산자 왼쪽에 있는 값입니다.
더 자세한 설명은 특별 메소드 글을 참조하세요.
연습 문제
NotImplementedError
와NotImplemented
의 차이를 설명하세요.
- 프롤로그
- 개발 첫걸음
- 파이썬 기초
- 파이썬 중급
- 파이썬 고급
- 내장 함수 톺아보기
- 예외와 에러 – 예상치 못한 상황에 대응하기 (v0.1)
- 변수의 범위 – 이름 검색의 범위
- 파이썬 심화
- 시퀀스와 반복자 – 반복과 순회를 자유자재로 다루기
- 데코레이터 – 함수의 기능을 강화하기
- 프로퍼티
- 제너레이터
- async와 await
- 객체로서의 클래스 – 클래스를 동적으로 정의하기
- 파이썬 프로젝트 실습
- 원카드 게임 만들기 (1)
- 원카드 게임 만들기 (2)
- 원카드 게임 만들기 (3) (작성중)
- 턴제 자동 전투 게임 만들기 (작성중)
- 실전 (파이썬 외적인 것들)
- 정규표현식 – 문자열을 검색하고 치환하기 (작성중)
- 유니코드 – 컴퓨터에서 문자를 표기하는 방법
- html, css, 인터넷 – 자동화 첫 걸음 내딛기
- 네트워크 – 인터넷으로 통신하는 방법
- 문서 – 문맥을 읽어보기