매직 메서드

2025. 1. 29. 18:38공부 정리

매직 메서드(던더 매서드)가 익숙하지 않아서 따로 정리한다.

몰랐을 때는 쓰면서도 굳이 언더바를 추가해서 보낼 필요가 있나 하는 생각이 마음 한켠에 항상 있었는데, 퍼플에 물어보니 매직 메서드를 쓰지 않으면 리턴값에 해당 연산자 혹은 매서드를 쓸 수 없다고 한다. 파이썬은 자바스크립트나 욜로 모델과는 다르게 데이터로더, 토치라이트닝에서 쓰듯이 미리 지정해 주어야 사용이 가능하다.

 

class CustomList:
    def __init__(self, name, items):
        """객체 초기화"""
        self.name = name
        self.items = items  # 리스트 형태의 데이터

    def __str__(self):
        """객체의 사용자 친화적인 문자열 표현"""
        return f"CustomList(name={self.name}, items={self.items})"
    def __repr__(self):
        """객체의 공식적인 문자열 표현 (디버깅용)"""
        return f"CustomList({repr(self.name)}, {repr(self.items)})"

    def __len__(self):
        """객체의 길이를 반환 (items의 길이)"""
        return len(self.items)

    def __getitem__(self, index):
        """인덱싱 가능하게 구현"""
        return self.items[index]
    def __setitem__(self, index, value):
        """인덱스에 값 할당 가능하게 구현"""
        self.items[index] = value

    def __iter__(self):
        """이터레이터 반환"""
        return iter(self.items)
    def __next__(self):
        """다음 이터레이터 값 반환 (예: next())"""
        if not hasattr(self, "_iter"):
            self._iter = iter(self.items)
        return next(self._iter)

    def __add__(self, other):
        """덧셈 연산 (+ 연산자)"""
        if isinstance(other, CustomList):
            combined_name = f"{self.name} + {other.name}"
            combined_items = self.items + other.items
            return CustomList(combined_name, combined_items)
        return NotImplemented

    def __call__(self, *args, **kwargs):
        """객체를 함수처럼 호출 가능하게 구현"""
        print(f"{self.name} was called with args={args} and kwargs={kwargs}")

    def __del__(self):
        """객체 소멸 시 호출"""
        print(f"CustomList '{self.name}' is being deleted.")

# 사용 예제
if __name__ == "__main__":
    # 객체 생성
    clist1 = CustomList("List1", [1, 2, 3])
    clist2 = CustomList("List2", [4, 5])

    # __str__ 및 __repr__
    print(str(clist1))  # 출력: CustomList(name=List1, items=[1, 2, 3])
    print(repr(clist2))  # 출력: CustomList('List2', [4, 5])

    # __len__
    print(len(clist1))  # 출력: 3

    # __getitem__, __setitem__
    print(clist1[0])  # 출력: 1
    clist1[0] = 10
    print(clist1[0])  # 출력: 10

    # __iter__, __next__
    for item in clist1:
        print(item)  # 출력: 10, 2, 3

    # __add__
    clist3 = clist1 + clist2
    print(clist3)  # 출력: CustomList(name=List1 + List2, items=[10, 2, 3, 4, 5])

    # __call__
    clist1(42, key="value")  
    # 출력: List1 was called with args=(42,) and kwargs={'key': 'value'}

# 객체 소멸 (__del__)
del clist1

 

 

# eq, lt
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def __eq__(self, other):
        return self.width * self.height == other.width * other.height

    def __lt__(self, other):
        return self.width * self.height < other.width * other.height

r1 = Rectangle(3, 4)
r2 = Rectangle(6, 2)
print(r1 == r2)  # 출력: True (넓이가 같음)
print(r1 < r2)   # 출력: False

## print의 각 연산자들과 클래스 내부의 정의와 연결.
## 클래스를 정의해서 들어온 뒤, 클래스 내부에서 연산자와 함수와 연결.

 

# enter, exit for file control
class FileManager:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        # 파일 열기
        self.file = open(self.filename, 'w')
        return self.file

    def __exit__(self, exc_type, exc_value, traceback):
        # 항상 파일을 닫아 리소스를 해제
        self.file.close()

# 사용 예시
with FileManager('test.txt') as f:
    f.write('Hello World!')
    
## 파일을 열고, 라인을 입력한 뒤, 저장 후, 닫는 단계 진행.

 

728x90