공부 정리

매직 메서드

jjnll 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