CodeGym /행동 /Python SELF KO /연산자 오버로딩

연산자 오버로딩

Python SELF KO
레벨 20 , 레슨 0
사용 가능

6.1 매직 메서드

Python의 연산자 오버로딩은 사용자 정의 클래스의 기본 연산자(예: +, -, *, /)의 동작을 정의하거나 변경할 수 있게 해줘. 이 작업은 매직 메서드라고도 불리는 특별한 메서드를 사용해서 진행돼.

예를 들어, 클래스에서 비교 연산자를 오버로딩할 수 있어:

연산자 메서드 명 메서드 시그니처
== eq() __eq__(self, other)
!= ne() __ne__(self, other)
< lt() __lt__(self, other)
<= le() __le__(self, other)
> gt() __gt__(self, other)
>= ge() __ge__(self, other)

만약 너가 클래스를 만들고 그 클래스의 객체들을 네가 원하는 방법으로 비교하고 싶다면, 그냥 그 클래스에 «__eq__» 메서드를 구현하면 돼. 그러면 Python은 너의 클래스 객체들이 코드에서 비교될 때마다 이 메서드를 호출할 거야.

예시:


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
        
# 사용 예시
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2)  # 출력: True
print(v1 == v3)  # 출력: False

네 객체 두 개를 비교할 때마다, Python은 그들이 함수 «__eq__»를 구현했는지 확인해. 만약 있다면, 그걸 호출하지. 없는 경우엔, 그냥 객체 참조를 비교할 거야.

사실 위의 예시는 이런 식으로 작성된 것과 다를 바 없지 (메서드 존재 여부를 체크하는 부분만 추가해야겠지):


# 사용 예시
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # 출력: True
print(v1.__eq__(v3))  # 출력: False

6.2 모든 연산자 목록

총 6개 그룹의 연산자들이 오버로딩 가능해.

산술 연산자:

연산자 메서드 명 메서드 시그니처
+ add __add__(self, other)
- sub __sub__(self, other)
* mul __mul__(self, other)
/ truediv __truediv__(self, other)
// floordiv __floordiv__(self, other)
% mod __mod__(self, other)
** pow __pow__(self, other)

비교 연산자:

연산자 메서드 명 메서드 시그니처
== eq __eq__(self, other)
!= ne __ne__(self, other)
< lt __lt__(self, other)
<= le __le__(self, other)
> gt __gt__(self, other)
>= ge __ge__(self, other)

논리 연산자:

연산자 메서드 명 메서드 시그니처
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

인덱싱 및 슬라이싱 연산자:

연산자 메서드
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

단항 연산자:

연산자 메서드
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

할당 연산자:

연산자 메서드
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

아마도 Python이 느린 이유 중 하나는 연산자가 실행되기 전에 클래스 및 모든 부모 클래스에 해당하는 유사한 함수를 찾기 때문일 거야. 하지만 덕분에 세상에서 가장 컴팩트한 코드를 쓸 수 있지 :)

6.3 인덱싱 연산자

객체를 비교하거나 세트를 빼는 게 좀 더 눈에 띄지. 그리고 논리적 또는 수학적 연산이 필요한 클래스를 작성할 때도 자연스럽게 알게 될 거야.

재밌는 예시 하나를 좀 보자 - 인덱싱 연산자. 바로 코드 예시부터 시작해보자:


class CustomList:
    def __init__(self, data):
        self.data = data
        
    def __getitem__(self, index):
        return self.data[index]
        
    def __setitem__(self, index, value):
        self.data[index] = value
        
    def __delitem__(self, index):
        del self.data[index]
        
    def __repr__(self):
        return repr(self.data)
        
# 사용 예시
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1])  # 출력: 2
c_list[1] = 10
print(c_list)  # 출력: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # 출력: [1, 3, 4, 5]

여기선 세 가지 작업을 볼 수 있어:

  • 인덱스로 데이터 읽기
  • 인덱스로 데이터 쓰기
  • 그리고 인덱스로 데이터 삭제하기까지.

그리고 데이터가 리스트 형태로 저장될 필요는 없어. 또한 인덱스가 반드시 숫자일 필요도 없지. 예를 들어, dictionary (딕셔너리) 클래스가 바로 그런 식으로 구현돼 있어.

SuperList 생성하기

list 클래스 기억나? 이미 있는 인덱스에만 할당이 가능했지. 이제 내 클래스를 만들어 보자, 이름은 SuperList로 하고, 어떤 인덱스든 접근할 수 있게 만들어보자:

  • 인덱스가 < 0이면, 요소를 처음에 삽입
  • 인덱스가 >= len이면, 요소를 끝에 추가
  • 나머지 경우에는, 그냥 요소를 반환

예시:


class SuperList(list):
    def __init__(self, value):
        super().__init__(value)
        
    def __setitem__(self, index, value):
        if index >= len(self):
            super().append(value)
        elif index < 0:
            super().insert(0, value)
        else:
            super().__setitem__(index, value)
        
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst)  # [99, 1, 2, 3, 100]

인덱스 오버로딩은 정말 좋은 기능이야, 실제로 사용해보길 추천해. 오늘은 이만 마치자.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION