본문 바로가기
Software/Python

[파이썬의 기본] 마술 함수(?) 매직 메소드 (Magic Methods )

by lovey25 2019. 6. 24.
반응형

Magic Methods

매직 메소드는 함수이름 앞과 뒤에 언더스코어(_) 두개가 연속으로 붙어있는 함수를 말합니다. 그러니까 “__name__” 이런식의 형태인데 앞에서 클래스를 예기하면서 컨스트럭터 매소드인 “__init__” 이 그런형태를 취하고 있었습니다. 이런 형태의 마법함수는 파이썬에서 그 이름을 미리 지정해 둔 사저예약함수들도 그 기능이 정해져 있습니다.

사용법

이런 마법함수는 어떤때 사용할까요? 먼저 가장 일반적인 용도는 오퍼레이터의 오버로딩용입니다. 오버로딩이라는 단어에 익숙하신 분들은 그 의미를 금새 알아차리실 수 있을텐데요. 저는 아직 초보라 예제를 보고나서 이해를 했습니다.

얼른 예제를 보겠습니다.

예제:

class coordinate:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  def __add__(self, other):
    return coordinate(self.x + other.x, self.y + other.y)

coord1 = coordinate(5, 7)
coord2 = coordinate(3, 9)
coord3 = coord1 + coord2
print(coord3.x)
print(coord3.y)

"coordinate"라는 클래스인데요 내부에 "__init__"와 "__add__" 두가지의 함수가 들어있습니다. 첫번째는 익숙한 생성자이죠?! 두개의 오퍼레이터를 받아서 내부의 x, y 변수를 초기화 하는데 사용됩니다. 그리고 두번째 __add__ 함수 부분이 좀 아리까리 한데 그 아래 사용형태와 결과를 먼저 보겠습니다.

먼저 x값 5와 y값 7인 객체를 만들어서 "coord1"이라는 변수에 할당을 했습니다. 그리고 마찬가지로 "coord2"에는 x는 3, y는 9값이 들어가있는 객체가 되었습니다. 10행에서는 이 두객체를 더하고 11행과 12행에서 x, y를 각각 출력하도록 하고 있는데요. 신기하게도 x는 x끼리 더해지고 y는 y끼리 더해진 결과를 확인할 수 있습니다.

결과:

"__add__"라는 함수는 클래스 안에서 더하기(+)연산자 역할을 하게되는데요. "coord1 + coord2"는 다음과 같은 형태로 풀어쓸 수 있습니다. "coord1.__add__(coord2)" 그래서 self는 coord1, other변수에는 coord2가 들어가서 self와 other로 지칭한 두개의 숫자 묶음을 x는 x끼리, y는 y끼리 더하기를 해서 "coordinate"클래스 객체형태로 반환하도록 한다는 뜻입니다. 표현형이 아직 직관적으로 다가오지 않아서 좀더 많은 연습이 필요할 것 같습니다.

__add__ 외에도 다음과 같은 연산자들이 마법함수로 사용됩니다.

__sub__ -
__mul__ *
__truediv__ /
__floordiv__ //
__mod__ %
__pow__ **
__and__ &
__xor__ ^
__or__ |
__lt__ <
__le__ <==
__eq__ ==
__ne__ !=
__gt__ >
__ge__ >=

또다른 예제를 하나더 가져왔는데 살펴보도록 하겠습니다.

예제:

class SpecialString:
  def __init__(self, cont):
    self.cont = cont

  def __gt__(self, other):
    for index in range(len(other.cont)+1):
      result = other.cont[:index] + ">" + self.cont
      result += ">" + other.cont[index:]
      print(result)

spam = SpecialString("spam")
eggs = SpecialString("eggs")
spam > eggs

마지막 줄에 "spam"과 "eggs"라는 "SepcialString" 객체가 ">" 기호로 연결이 되어 있는데 ">"기호는 클래스 안에서 "__gt__" 라는 매직함수로 오버로딩되도록 되어 있습니다.

그리고 5행부터 9행까지의 코드를 보면 "other"로 받게되는 객체는 "eggs"이고 "eggs"안에는 'eggs'라는 문자열이 저장되어 있습니다. 여기서 'eggs'라는 문자열의 길이만큼 반복으로 하면서 앞에서부터 차례대로 단어를 두동강내고 있는데요. "index"가 2라고 가정을 하고, 7, 8행을 다시써보면 다음과 같겠죠.

other.cont[:index] + 	# eg
">" + 					# >
self.cont +				# spam
">" + 					# >
other.cont[index:]		# gs

그래서 결과는 다음과 같습니다.

결과:

클래스를 컨터에너처럼 만들어주는 매직함수들도 있습니다.

__len__ len()
__getitem__ indexing
__setitem__ assigning to indexed values
__delitem__ deleting indexed values
__iter__ iteration over object
__contains__ in

그외에대 더 많은 마법의 함수들이 있지만 예제 하나만 더 살펴보고 마무리 하겠습니다.

예제:

import random

class VagueList:
  def __init__(self, cont):
    self.cont = cont

  def __getitem__(self, index):
    return self.cont[index + random.randint(-1, 1)]

  def __len__(self):
    return random.randint(0, len(self.cont)*2)

vague_list = VagueList(["A", "B", "C", "D", "E"])
print(len(vague_list))
print(len(vague_list))
print(vague_list[2])
print(vague_list[2])

결과1:

결과2:

14, 15행과 16, 17행이 서로 같은 코드인데 각각 결과값이 다르죠? 그리고 2번의 실행결과도 서로 다릅니다. 이 예제에서는 문자열 길이를 반환하는 "len()"함수와 리스트의 인덱스 자체도 오버로딩시켜서 그 원래 기능과 다르게 동작하도록 하고있습니다.

 

끝!

반응형

댓글