연산자 오버로딩

개념

  • Operator overloading
  • 정의 : 내장된 기본 연산자의 동작을 클래스 내에서 재정의(Overriding)하여, 별도 의도된 작업을 처리하도록 하는 기법
  • 쉽게 말해, 원래 파이썬에서 사용되는 연산자의 작동 방식을 직접 정의해 덮어씌운 것

예시

(1) 파이썬 기본 문법

동일한 연산자가 데이터 타입에 따라 다르게 동작하는 기본적인 사례

  • + 연산자 : 숫자형에서는 덧셈의 역할, 문자열에서는 결합(concatenation) 역할
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# --- add 연산자 (정수형) --- #
print(1+1)
# >> 2

# --- add 연산자 (부동소수형) --- #
print(3.14 + 5.676)
# >> 8.816

# --- add 연산자 (문자형) --- #
print('a' + 'b')
# >> ab

# --- add 연산자 (문자열) --- #
print("abc" + "def")
# >> abcdef
  • * 연산자 : 숫자형에서는 곱셈의 역할, 문자열에서는 반복(repeat) 역할
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# --- mul 연산자 (정수형) --- #
print(3*2)
# >> 6

# --- mul 연산자 (부동소수형) --- #
print(3.14 * 5.676)
# >> 17.82264

# --- mul 연산자 (문자형 * 정수형) --- #
print('a' * 3)
# >> aaa

# --- mul 연산자 (문자열 * 정수형) --- #
print("abc" * 2)
# >> abcabc

Apache Airflow

  • Airflow 에서는 > 연산자를 통해 태스크 파이프라인(DAG)을 정의한다.
1
2
3
start > task1 > group1 > integration_task > end
start > task1 > group2 > integration_task > end
start > task1 > group3 > end

LCEL

  • LCEL(LangChain Expression Language) 에서는 | 연산자를 통해 흐름(Chain)을 정의한다.
1
chain = prompt | llm | parser



사용자 정의 연산자 오버로딩

연산자의 원리

  • 사용자 정의 연산자를 살펴보기 전에, 특정 클래스에서의 연산자들이 어떻게 정의되는지 살펴본다.
  • 클래스에서 각 연산자는 __add__(더하기 연산자) __mul__(곱하기 연산자) 등의 매직 메서드로 정의된다.
1
2
3
4
5
6
7
class Test:
    
    def __init__(self, a:int):
        self.a = a
        
    def __add__(self, other:int):
        return self.a + other.a


연산자 매직 메서드의 종류

  • 사칙연산 Arithmetic Operators
연산자 메서드 이름풀이
+ __add__(self, other) add
- __sub__(self, other) subtract
* __mul__(self, other) multiply
/ __truediv__(self, other) true divide
// __floordiv__(self, other) floor divide
% __mod__(self, other) modulo
** __pow__(self, other) power
  • 비교연산 Comparison Operators
연산자 메서드 이름풀이
< __lt__(self, other) less than
> __gt__(self, other) greater than
<= __le__(self, other) less than or equal to
>= __ge__(self, other) greater than or equal to
== __eq__(self, other) equal
!= __ne__(self, other) not equal
  • 대입 연산자 Assignment Operator
연산자 메서드 이름풀이
+= __iadd__(self, other) in-place(그 자리에서) add
-= __isub__(self, other) in-place subtract
*= __imul__(self, other) in-place multiply
/= __itruediv__(self, other) in-place true divide
//= __ifloordiv__(self, other) in-place floor divide
%= __imod__(self, other) in-place modulo
**= __ipow__(self, other) in-place power
  • 단항연산자 Unary Operators
연산자 메서드 이름풀이
- __neg__(self) negative
+ __pos__(self) positive
~ __invert__(self) invert
  • 불리언 연산자 Boolean Operator
연산자 메서드 이름풀이
& __and__(self) and
| __or__(self) or


사용자 정의 연산자 만들어보기

  • 덧셈을 곱셈으로 만들기
1
2
3
4
5
6
7
8
9
class Test:
    def __init__(self, a:int):
        self.a = a
    def __add__(self, other:int):
        return self.a + other.a

t1 = Test(3)
t2 = Test(5)
print(t1 + t2)
1
15


LangChain의 파이프라인 재현해보기

  • LCELObject : Prompt, LLM, Parser 와 같은 LCEL 표현법의 오브젝트들
  • Chain : LCEL 오브젝트들의 선후관계를 묶은 체인
  • LCELObject 들은 모두 process라는 작업 실행 메서드를 가지고 있음
  • Chain 은 전체 파이프라인을 실행시키는 invoke라는 메서드를 가지고 있음
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
from abc import ABC, abstractmethod

class LCELObject(ABC):
    def __or__(self, next_object):
        return Chain(self, next_object)
    @abstractmethod
    def process(self, something):
        pass

class Chain:
    def __init__(self, first, second):
        self.first = first
        self.second = second
    def invoke(self, data):
        first_result = self.first.process(data)
        final_result = self.second.process(first_result)
        return final_result

class Prompt(LCELObject):
    def __init__(self, prompt):
        self.prompt = prompt
    def process(self, data:str):
        if data is not None:
            self.prompt = data
        return self.prompt

class LLM(LCELObject):
    def __init__(self, config):
        self.config = config
        self.name = config.get("name")
    def process(self, data):
        return self.name + f" AI 응답 : {data}에 대한 AI 응답입니다."
  • prompt와 llm 설정을 지정한 뒤 실행
1
2
3
4
5
6
prompt = Prompt("당신은 사용자를 돕는 상담사입니다.")
llm = LLM({"name":"샘플 LLM"})

chain = prompt | llm
result = chain.invoke("안녕하세요?")
print(result)
1
샘플 LLM AI 응답 : 안녕하세요?에 대한 AI 응답입니다.

Reference

https://www.geeksforgeeks.org/python/operator-overloading-in-python/

Comments