Published on

Python Magic Method 를 활용한 객체 지향 프로그래밍

Authors

Python에서 Magic Method(매직 메서드)는 언더스코어(_) 2개를 붙여서 표기하는 함수이고, 클래스에서 정의 합니다.

특정 상황이나 연산이 발생할 때 자동으로 호출, 이것이 왜 필요하고 어떻게 동작하는지 정리했습니다.

1. Magic Method(매직 매서드)란?

매직 메서드는 파이썬의 여러 내장 함수나 연산자와 연결되어있습니다.

해당 함수나 연산자가 사용될 때 자동으로 호출됩니다. (ex: ==, len() 등등)

이는 파이썬 인터프리터가 이러한 메서드들을 인식하고, 적절한 상황에서 호출하기 때문입니다.

객체를 문자열로 표현할 때 __str__ 메서드가 호출되고, 두 객체를 비교할 때 __eq__ 메서드가 호출됩니다. 간단한 예시로 djangomodel 에서도 __str__ 을 통해서 어떤 객체인지 알 수 있어, 객체에 대한 정체를 파악하기가 쉽습니다.

2. Magic Method(매직 매서드)의 동작 원리

파이썬의 연산자나 함수가 사용될 때, 해당 객체의 클래스에 매직 메서드가 정의되어 있는지 먼저 확인합니다.

만약 정의되어 있다면, 이를 호출하여 적절한 동작을 수행합니다.

예를 들어 obj1 == obj2 이 실행될때, 인터프리터는 obj1의 클래스에 같은 것인지 판단해주는 역할의 __eq__ 메서드가 정의되어 있는지 확인하고, 정의되어 있다면 이를 호출하여 두 객체가 같은지 비교합니다.

3. 자주쓰는 Magic Method(매직 매서드)

여러 매직 메서드 중에서도 자주 사용되는 몇 가지를 통해서 자세하게 알아보겠습니다.

init

클래스를 초기화 하는 함수라는 정의를 갖고있고,이는 곧 클래스에서 기본적으로 사용되는 값들을 self로 지정해주는 정체성(?)을 갖는 함수입니다.

객체가 생성될 때 호출됩니다.


class MagicClass:
    def __init__(self, level):
        self.level = level

obj = MagicClass(10)  # MagicClass.__init__() 호출

str

print 함수나 str() 함수가 호출될 때 실행됩니다.


class MagicClass:
		# 생략
    def __str__(self):
        return f"MagicClass LV.{self.level}"

obj = MagicClass(10)
print(obj)  # MagicClass.__str__() 호출되어 MagicClass LV.10

eq

== 연산자가 사용될 때 호출됩니다.

class MagicClass:
		# 생략
    def __eq__(self, other):
        return self.value == other.value

obj1 = MagicClass(10)
obj2 = MagicClass(10)
print(obj1 == obj2)  # MagicClass.__eq__() 호출되어 같은지 확인

getitem

객체가 인덱스로 접근될 때 호출됩니다.

class MagicClass:
    def __init__(self, level):
        self.level = level

    def __getitem__(self, index):
        return self.value[index]

obj = MagicClass([1, 2, 3])
print(obj[1])  # MagicClass.__getitem__() 호출

4. 매직 메서드 - CustomList

다음은 주요 매직 메서드를 활용한 CustomList 클래스의 예시입니다.

이 클래스는 기본 리스트와 유사하지만, 다양한 매직 메서드를 통해 동작을 확장합니다.

class CustomList:
    def __init__(self, *args):
        self.items = list(args)

    def __str__(self):
        return f"CustomList: {self.items}"

    def __repr__(self):
		    # 컴프리헨션으로 풀어서 보여주는 예시 입니다.
        return f"CustomList({', '.join(repr(item) for item in self.items)})"

    def __eq__(self, other):
        if isinstance(other, CustomList):
            return self.items == other.items
        return False

    def __lt__(self, other):
        if isinstance(other, CustomList):
            return self.items < other.items
        return False

    def __len__(self):
        return len(self.items)

    def __getitem__(self, index):
        return self.items[index]

    def __setitem__(self, index, value):
        self.items[index] = value

    def __delitem__(self, index):
        del self.items[index]

clist = CustomList(1, 2, 3, 4)

# __str__ 및 __repr__ 메서드 사용
print(clist)  # CustomList: [1, 2, 3, 4]
print(repr(clist))  # CustomList(1, 2, 3, 4)

# __eq__ 및 __lt__ 메서드 사용
clist2 = CustomList(1, 2, 3, 4)
print(clist == clist2)  # True

clist3 = CustomList(1, 2, 3)
print(clist < clist3)  # False

# __len__ 메서드 사용
print(len(clist))  # 4

# __getitem__, __setitem__, __delitem__ 메서드 사용
print(clist[2])  # 3

clist[2] = 10
print(clist)  # CustomList: [1, 2, 10, 4]

del clist[2]
print(clist)  # CustomList: [1, 2, 4]

5. 매직 메서드 - LoggingList

이번에는 요소를 추가하거나 삭제할 때마다 로그를 기록하는 LoggingList 클래스를 만들어 보겠습니다.

class LoggingList:
    def __init__(self, *args):
        self.items = list(args)
        self.log = []

    def __str__(self):
        return f"LoggingList: {self.items}"

    def __repr__(self):
        return f"LoggingList({', '.join(repr(item) for item in self.items)})"

    def __getitem__(self, index):
        return self.items[index]

    def __setitem__(self, index, value):
        self.log.append(f"Set(업데이트) Log : index {index} to {value}")
        self.items[index] = value

    def __delitem__(self, index):
        self.log.append(f"Delete(삭제) Log item at index {index}")
        del self.items[index]

    def append(self, value):
        self.log.append(f"Appended {value}")
        self.items.append(value)

    def get_log(self):
        return self.log

llist = LoggingList(1, 2, 3)

# 요소 추가 및 로그 확인
llist.append(4)
print(llist)  # LoggingList: [1, 2, 3, 4]
print(llist.get_log())  # ['Appended 4']

# 요소 수정 및 로그 확인
llist[1] = 10
print(llist)  # LoggingList: [1, 10, 3, 4]
print(llist.get_log())  # ['Appended 4', 'Set index 1 to 10']

# 요소 삭제 및 로그 확인
del llist[2]
print(llist)  # LoggingList: [1, 10, 4]
print(llist.get_log())  # ['Appended 4', 'Set index 1 to 10', 'Deleted item at index 2']

6. 매직 메서드의 활용

매직 메서드는 파이썬의 객체 지향 프로그래밍을 강력하고 유연하게 만들어주는 중요한 기능 중 하나입니다.

이를 통해 객체의 특정 동작을 사용자 정의할 수 있으며, 다양한 상황에 맞게 클래스를 확장할 수 있습니다.

매직 메서드를 잘 활용하면, 파이썬의 다양한 연산과 함수 호출에서 객체의 동작을 더욱 직관적이고 자연스럽게 만들수도 있고, 그 안에서 원하는 비즈니스 로직이 있다면 추가 할 수도 있습니다.

만약 == 등의 연산에서 필요하거나 추가하고 싶은 로직이 있다면 매직 메서드를 정의해서 해당 상황이 발생할 때 파이썬이 자동으로 이를 호출하여 적절한 동작을 수행할 수 있도록 하는 것 입니다.

이를 통해 객체 지향 프로그래밍의 강력한 도구를 사용할 수 있습니다.

hongreat 블로그의 글을 봐주셔서 감사합니다!