본문 바로가기
프로그래밍 언어/Python

[Python] 매직 메소드를 통한 기능 구현

by 토마토베이컨수프 2021. 9. 29.

매직 매소드란?

클래스 안에 있는 특별한 메소드 이며 대표적인 예로 __init__, __str__ 메소드가 있습니다.

 

a = 1
b = 2
print(a + b)	# 3

그리고, 예를 들어 위 코드처럼 a 와 b 는 각각 1 과 2를 할당한 순간 a, b는 int 클래스의 인스턴스가 되고, int 클래스 내부의 __add__ 매직 메소드에 따라 a+b를 직접적으로 연산할 수 있는 것입니다.

 

class Practice:
    def __init__(self, value):
        self._value = value


a = Practice(1)
b = Practice(2)
print(a + b)	# TypeError

그러나 이렇게 사용자 정의로 만들어준 클래스에 대해선 __add__ 매직 메소드가 구현되지 않았기 때문에 두 인스턴스에 대해서 곧바로 + 연산자를 사용할 수 없습니다.

 

class Practice:
    def __init__(self, value):
        self._value = value

    def __add__(self, other):
        return self._value + other._value


a = Practice(1)
b = Practice(2)
print(a + b)	# 3

만약 이렇게 __add__ 매직 메소드를 추가해 내부 구현을 해주게 된다면 두 인스턴스간에 + 연산을 바로 적용할 수 있게 됩니다.

 

 

이와 같이 다른 다양한 종류의 매직 메소드들도 하나하나 살펴보며 구현해보도록 하겠습니다.

 


__getitem__

__getitem__ 매직 메소드는 리스트나 튜플에 슬라이싱을 적용할 수 있게 하는 메소드 입니다.

class Items:
    def __init__(self, *values):
        self._values = list(values)

    def __getitem__(self, item):
        return self._values.__getitem__(item)
        
        
c = Items(1, 2, 3, 4, 5, 6, 7)
print(c[:3])	# [1, 2, 3]

 


__enter__ , __exit__

어떤 파일을 읽을 때, 중간에 예외가 발생하면 그대로 파일을 자동으로 닫아주는 기능을 하는 with문을 적용할 수 있는 매직 메소드 입니다. 만약 파일을 닫아 주지 않는다면 프로그램이 종료되어도 파일은 계속 열려있는 문제가 발생할 수 있기 때문이죠.

f = open("file.txt", "r")
try:
	print(f.readlines())
finally:
	f.close()
    
# 같은 내용의 코드 입니다.
with open("file.txt", "r") as f:
	print(f.readlines())

__enter__ 매직 메소드는 with문에 진입할 때 자동으로 호출되고, __exit__매직 메소드는 with문을 나올 때 자동으로 호출됩니다. 

이 원칙을 이용하여 with문을 자동으로 인식하여 파일을 읽고 닫는 간단한 클래스를 구현해 보겠습니다.

class FileReader:
    def __init__(self, file):
        self._file = file

    def __enter__(self):
        self._status = open(self._file, "r")
        return self._status

    def __exit__(self, type, value, traceback):
        self._status.close()
        
        
with FileReader("file.txt") as f:
	print(f.readlines())

 


__iter__

__iter__ 매직 메소드는 인스턴스를 반복할 때 호출되는 메소드로 인스턴스를 반복 가능하게 만들어 줍니다.

class NumIter:
    def __init__(self, value_1, value_2):
        self._start = value_1
        self._end = value_2

    def __iter__(self):
        point = self._start
        while point < self._end:
            yield point
            point += 1
            
            
for i in NumIter(1, 10):
    print(i, end="")	# 123456789

 


__contains__

__contains__ 매직 메소드는 in 문을 인식해 Boolean 값을 반환하는 메소드 입니다.

class Detector:
    def __init__(self, items):
        self._items = items

    def __contains__(self, item):
        return item in self._items


print(3 in Detector(range(1, 10)))	# True

 


__getattr__

__gettattr__은 인스턴스의 특정 속성을 호출할 때, 그 속성이 없으면 대신 호출되는 매직 메소드 입니다.

class Attributer:
    def __init__(self, name):
        self.name = name

    def __getattr__(self, attr):
        return attr + " not found"
        
        
attr = Attributer("Mike")
print(attr.name)	# Mike
print(attr.wrongname)	# wrongname not found

 

 


__call__

__call__ 매직 메소드는 인스턴스를 일반 함수처럼 호출이 가능하도록 만들어 줍니다.

아래 코드는 __call__을 이용해 특정 값으로 인스턴스가 몇 번 호출되었는지 리턴하는 클래스를 구현한 것입니다.

class Counter:
    def __init__(self):
        self._count = {}

    def __call__(self, value):
        try:
            self._count[value] += 1
        except KeyError:
            self._count[value] = 1
        return self._count[value]
        
        
counter = Counter()
print(counter(1))	# 1
print(counter(2))	# 1	
print(counter(1))	# 2

 


 

참고 자료

  • <파이썬 클린 코드 : 유지보수가 쉬운 파이썬 코드를 만드는 비결, 마리아노 아나야 지음>
  • 파이썬의 컨텍스트 매니저 (Context Manager) 에 대해 알아봅시다. - https://sjquant.tistory.com/12

'프로그래밍 언어 > Python' 카테고리의 다른 글

[Python] 제너레이터  (0) 2021.11.11
[Python] 유용한 데이터 구조  (0) 2021.11.07
[Python] 파이썬 다운 코딩  (0) 2021.11.05
[Python] SOLID 원칙  (0) 2021.10.03
[Python] 파이썬 프로그래밍의 개발 지침  (0) 2021.10.01