Python-Special Methods

클래스에 특별한 기능을 부여하는 특수한 메소드.
언더스코어 두 개로 둘러싸인 이름을 가지며, 파이썬 인터프리터에 의해 특정 상황에서 자동으로 호출된다.

객체 생성 및 초기화

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Example:
    def __new__(cls, *args, **kwargs):
        # 객체 생성 전에 호출되는 메서드
        print("1. __new__ 호출: 객체 생성")
        # 실제 객체 생성
        instance = super().__new__(cls)
        return instance

    def __init__(self, value):
        # 객체 초기화 메서드
        print("2. __init__ 호출: 객체 초기화")
        self.value = value

    def __del__(self):
        # 객체가 소멸될 때 호출되는 메서드
        print("3. __del__ 호출: 객체 소멸")

# 사용 예시
obj = Example(10)  # __new__와 __init__ 호출
del obj  # __del__ 호출

객체 표현

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        # 사용자 친화적인 문자열 표현
        return f"{self.name} ({self.age}세)"

    def __repr__(self):
        # 개발자를 위한 상세한 문자열 표현
        return f"Person(name='{self.name}', age={self.age})"

    def __format__(self, format_spec):
        # 형식화된 문자열 표현
        if format_spec == 'brief':
            return f"{self.name}"
        return str(self)

# 사용 예시
person = Person("홍길동", 30)
print(str(person))  # __str__ 호출
print(repr(person))  # __repr__ 호출
print(format(person, 'brief'))  # __format__ 호출

__str____repr__의 차이

특징strrepr
목적사용자 친화적 출력개발자 친화적 출력
사용print() 함수디버깅, 개발
상세도간단한 설명상세한 정보
형식읽기 쉬운 형식정확한 정보 포함

연산자 오버로딩

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        # + 연산자
        return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        # - 연산자
        return Vector(self.x - other.x, self.y - other.y)

    def __mul__(self, scalar):
        # * 연산자
        return Vector(self.x * scalar, self.y * scalar)

    def __truediv__(self, scalar):
        # / 연산자
        return Vector(self.x / scalar, self.y / scalar)

    def __floordiv__(self, scalar):
        # // 연산자
        return Vector(self.x // scalar, self.y // scalar)

    def __mod__(self, scalar):
        # % 연산자
        return Vector(self.x % scalar, self.y % scalar)

    def __pow__(self, power):
        # ** 연산자
        return Vector(self.x ** power, self.y ** power)

    def __lshift__(self, other):
        # << 연산자
        return self.x << other.x, self.y << other.y

    def __rshift__(self, other):
        # >> 연산자
        return self.x >> other.x, self.y >> other.y

    def __and__(self, other):
        # & 연산자
        return self.x & other.x, self.y & other.y

    def __or__(self, other):
        # | 연산자
        return self.x | other.x, self.y | other.y

    def __xor__(self, other):
        # ^ 연산자
        return self.x ^ other.x, self.y ^ other.y

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # 벡터 덧셈
print(v1 * 2)   # 벡터 스칼라 곱

단항 연산자

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Number:
    def __init__(self, value):
        self.value = value

    def __pos__(self):
        # 단항 + 연산자
        return Number(+self.value)

    def __neg__(self):
        # 단항 - 연산자
        return Number(-self.value)

    def __abs__(self):
        # abs() 함수
        return Number(abs(self.value))

    def __invert__(self):
        # ~ 연산자
        return Number(~self.value)

n = Number(5)
print(abs(n).value)  # 절대값
print((~n).value)    # 비트 반전

비교 연산자

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    def __eq__(self, other):
        # == 연산자
        return self.celsius == other.celsius

    def __ne__(self, other):
        # != 연산자
        return self.celsius != other.celsius

    def __lt__(self, other):
        # < 연산자
        return self.celsius < other.celsius

    def __le__(self, other):
        # <= 연산자
        return self.celsius <= other.celsius

    def __gt__(self, other):
        # > 연산자
        return self.celsius > other.celsius

    def __ge__(self, other):
        # >= 연산자
        return self.celsius >= other.celsius

t1 = Temperature(20)
t2 = Temperature(25)
print(t1 < t2)  # 온도 비교

컨테이너 메소드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class CustomList:
    def __init__(self, items):
        self.items = items

    def __len__(self):
        # len() 함수
        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]

    def __iter__(self):
        # 이터레이션
        return iter(self.items)

    def __next__(self):
        # 다음 항목 반환
        if not self.items:
            raise StopIteration
        return self.items.pop(0)

    def __contains__(self, item):
        # in 연산자
        return item in self.items

cl = CustomList([1, 2, 3, 4, 5])
print(len(cl))  # 길이
print(cl[2])    # 인덱싱
print(3 in cl)  # 포함 여부

속성 접근

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class DynamicAttributes:
    def __init__(self):
        self._attributes = {}

    def __getattr__(self, name):
        # 존재하지 않는 속성 접근
        return self._attributes.get(name, None)

    def __setattr__(self, name, value):
        # 속성 설정
        if name == '_attributes':
            super().__setattr__(name, value)
        else:
            self._attributes[name] = value

    def __delattr__(self, name):
        # 속성 삭제
        del self._attributes[name]

    def __getattribute__(self, name):
        # 모든 속성 접근 시 호출
        print(f"Accessing attribute: {name}")
        return super().__getattribute__(name)

da = DynamicAttributes()
da.new_attr = 42
print(da.new_attr)
del da.new_attr

호출 가능 객체

1
2
3
4
5
6
7
class Adder:
    def __call__(self, x, y):
        # 객체를 함수처럼 호출
        return x + y

add = Adder()
print(add(3, 4))  # 객체를 함수처럼 사용

컨텍스트 관리

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class FileManager:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        # with 문 진입 시 호출
        self.file = open(self.filename, 'w')
        return self.file

    def __exit__(self, exc_type, exc_value, traceback):
        # with 문 종료 시 호출
        self.file.close()

with FileManager('test.txt') as f:
    f.write('Hello, World!')

피클링

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pickle

class Picklable:
    def __init__(self, value):
        self.value = value

    def __reduce__(self):
        # 객체의 직렬화 방법 정의
        return (self.__class__, (self.value,))

obj = Picklable(42)
pickled = pickle.dumps(obj)
unpickled = pickle.loads(pickled)
print(unpickled.value)

기타

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class CustomNumber:
    def __init__(self, value):
        self.value = value

    def __hash__(self):
        # hash() 함수
        return hash(self.value)

    def __bool__(self):
        # bool() 함수
        return bool(self.value)

    def __index__(self):
        # 정수형 변환
        return int(self.value)

cn = CustomNumber(42)
print(hash(cn))
print(bool(cn))
print(list(range(cn))[0])  # __index__ 사용

참고 및 출처