WeniVooks

검색

견고한 파이썬

매직 메서드

1. 매직 메서드

파이썬의 클래스에는 기본적으로 내장하고 있는 특별 메서드들이 있습니다. 파이썬에서는 이런 내장하고 있는 특별 메서드들을 쉽게 재정의하여 사용할 수 있게 되어있습니다.

마치 마법처럼 간단하게 수정할 수 있다고 해서 매직 매서드라고 부릅니다. 혹은 더블 언더바(__)를 2개 쓰고 있는 점에서 던더(dunder) 메서드라고도 부릅니다.

좌표평면의 점을 class로 구현해보았습니다. 우선 간단한 예제로 __add__를 살펴보도록 하겠습니다.

class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): print(self.x, self.y) return Point((self.x + other.x), (self.y + other.y)) dot1 = Point(10, 20) dot2 = Point(20, 30) dot3 = dot1 + dot2 print(dot3.x, dot3.y) # 출력: 30 50

+ 부호를 사용하여 덧셈을 할 때 dot1의 __add__ 메직메서드가 실행됩니다. print로 self의 x좌표와 y좌표를 출력함으로 알 수 있습니다.

매직 메서드 __init__은 앞에서도 살펴보았습니다. 이 매직 메서드는 인스턴스가 생성이 될 때 호출됩니다. 위 코드에서는 dot1과 dot2 인스턴스가 생성이 될 때 호출됩니다. 여기서 (10, 20), (20, 30)은 각각 인스턴스의 영역 self에 등록됩니다.

마찬가지로 곱하기도 구현할 수 있습니다. 곱하기는 __mul__로 구현할 수 있습니다. 다만 실제 곱하기를 구현하지는 않았습니다. 이는 실제 곱하기를 구현하지 않아도 된다는 것을 보여드리기 위함입니다.

class Point: def __init__(self, x, y): self.x = x self.y = y def __mul__(self, other): return 'hello' dot1 = Point(10, 20) dot2 = Point(20, 30) dot1 * dot2 # 출력: hello

이번에는 행렬의 연산을 구현한 예시로 살펴보도록 하겠습니다.

class Matrix: def __init__(self, value): self.value = value def __add__(self, other): result = [] for i in range(len(self.value)): result.append(self.value[i] + other.value[i]) return result def __mul__(self, other): if isinstance(other, int): return [i*other for i in self.value] raise TypeError('int형 외에 곱을 허락하지 않습니다!') m1 = Matrix([10, 20, 30]) m2 = Matrix([20, 30, 40]) print(m1 + m2) # 출력: [30, 50, 70] print(m1 * 3) # 출력: [30, 60, 90] # print(m1 * [1, 2, 3]) # error

위와 같은 예시를 통해 행렬의 덧셈, 뺄셈, 곱셈 등을 구현할 수도 있습니다.

이렇게 부호들은 클래스의 메직메서드와 연결되어 있습니다. 연산에 관련된 매직 메서드 공식 문서는 아래와 같습니다. 이러한 매직 메서드의 종류는 너무도 많기 때문에 필요에 따라 찾아보며 코딩합니다. 주요한 메서드는 아래 챕터에서 정리하도록 하겠습니다.

Data model (매직 메서드)

2. 주요한 매직 메서드

2.1. 생성자와 소멸자
  • __init__(self, ...): 객체가 생성될 때 호출되는 생성자 메서드
  • __del__(self): 객체가 소멸될 때 호출되는 소멸자 메서드
2.2. 문자열 표현
  • __str__(self): str() 함수 출력 결과와 같습니다. 이는 print로 출력되는 결과와도 동일합니다. 이 출력은 "공식적이지 않은" 또는 "좋게 보이는" 문자열 표현을 반환합니다. 객체의 공식적인 표현은 repr입니다.
  • __repr__(self): repr() 함수의 출력 결과와 같습니다. 객체의 "공식적인" 문자열 표현을 반환합니다.
2.3. 산술 연산
  • __add__(self, other): 덧셈 연산
  • __sub__(self, other): 뺄셈 연산
  • __mul__(self, other): 곱셈 연산
  • __truediv__(self, other): 나눗셈 연산(/)
2.4. 비교 연산
  • __eq__(self, other): 동등 연산 (==)
  • __ne__(self, other): 부등 연산 (!=)
  • __lt__(self, other): "작다" 연산 (<)
  • __le__(self, other): "작거나 같다" 연산 (<=)
  • __gt__(self, other): "크다" 연산 (>)
  • __ge__(self, other): "크거나 같다" 연산 (>=)
2.5. 컨테이너 타입 연산
  • __len__(self): len() 함수의 출력 결과와 같습니다.
  • __getitem__(self, key): 인덱싱 연산 (obj[key])의 출력 결과와 같습니다.
  • __setitem__(self, key, value): 항목 할당
  • __contains__(self, value): in 연산자
2.6. 호출 가능 객체
  • __call__(self, ...): 객체를 함수처럼 호출할 때 사용됩니다.

이 밖에도 많은 매직 메서드들이 있습니다. 이 메서드들을 오버라이드하여 사용자 정의 클래스의 동작을 원하는 대로 정의할 수 있습니다.

3. 매직 메서드 __call____getitem__ 예시

매직 메서드 __call__이나 __getitem__과 같은 형태는 어떻게 동작하는지 예시를 보지 않으면 그 사용법을 알기 힘듭니다. 어떻게 동작하는지 예시를 통해 보도록 하겠습니다.

class Counter: def __init__(self): self.count = 0 def __call__(self): self.count += 10 print(f'현재 count 값: {self.count}') def __getitem__(self, key): return key*10 # 객체 생성 counter = Counter() # 객체를 직접 호출합니다. 이때 __call__ 메서드가 실행됩니다. counter() # 출력: 현재 count 값: 10 counter() # 출력: 현재 count 값: 20 counter() # 출력: 현재 count 값: 30 counter[5] # 출력: 4

위 코드에서 __call__이 있기 때문에 인스턴스는 마치 함수처럼 호출할 수 있게 됩니다. 괄호의 형태로요. 그때마다 10이 더해지고 현재값을 출력합니다. return은 생략되어 있기 때문에 None입니다. 때문에 print를 했으면 None이 출력되었을 것입니다.

__getitem__이 있기 때문에 대괄호 안에 값을 넣어 출력할 수 있습니다. 대괄호 안에는 숫자 뿐만 아니라 문자나 객체가 들어갈 수도 있습니다. 이를 통해 좀 더 유연한 자료형을 만들 수도 있습니다.

{"packages":["numpy","pandas","matplotlib","lxml"]}
10.3 클래스 변수와 인스턴스 변수10.5 상속