Quark's Outlines: Python 강제 변환 규칙
I’m sorry, but I can’t retrieve the content from that external link. If you can provide the text you’d like translated, I’ll be happy to translate it into Korean for you while preserving the formatting and code blocks.
개요
Python에서 +, -, * 같은 이진 연산자를 사용할 때, 인터프리터는 서로 다른 타입일 수 있는 두 값을 어떻게 결합할지 결정해야 합니다. Python이 공통 타입이나 메소드를 찾기 위해 사용하는 과정을 coercion(강제 변환)이라고 합니다.
Python은 먼저 한 객체가 해당 연산을 처리할 수 있는지 확인합니다. 만약 그렇지 않다면, 다른 객체를 확인합니다. 특별한 경우에는 객체가 스스로 변환되어 다른 객체와 더 잘 작동하도록 할 수 있습니다.
print(3 + 5.0)
# 8.0
여기서 Python은 정수 3을 자동으로 부동소수점으로 강제 변환하여 덧셈을 수행합니다.
사용자 정의 객체를 섞어 사용할 때, Python은 클래스가 다른 객체와 결합하는 방식을 제어할 기회를 제공합니다. 객체가 __add__를 정의하면 Python은 먼저 그 메소드를 호출합니다. 만약 실패하면, 다른 객체의 __radd__ 메소드를 시도합니다.
이전 Python 버전에서는 __coerce__ 메소드를 정의하여 두 객체를 어떻게 호환시킬지 제안할 수 있었습니다. 이 메소드는 Python 3에서 제거되었지만, 이 패턴은 Python이 타입 혼합을 어떻게 생각하는지 보여줍니다.
class MyNumber:
def __radd__(self, other):
return f"Called with {other}"
print(5 + MyNumber())
# Called with 5
Python은 먼저 5.__add__()를 시도했지만 실패하고, 그 다음 MyNumber().__radd__(5)를 호출했습니다.
Historical Timeline
| 연도 | 주요 사건 |
|---|---|
| 1960 | FORTRAN에서 타입 승격을 통해 작은 타입을 변환하여 정수와 실수를 결합할 수 있게 되었습니다. |
| 1972 | C++의 Operator overloading은 사용자 정의 타입이 연산자 동작을 제어할 수 있게 했습니다. |
| 1991 | Python 0.9.0은 연산 전 암시적 변환을 위해 __coerce__를 도입했습니다. |
| 2000 | 리치 비교와 __add__ 및 __radd__와 같은 이진 메서드가 __coerce__를 대체했습니다. |
| 2008 | Python 3.0은 __coerce__를 제거하고 메서드 기반 강제 변환과 암시적 숫자 승격만 남겼습니다. |
| 2025 | 사용자 정의 타입과 혼합 연산을 위해 __op__와 __rop__ 메서드로 연산자 동작이 안정화되었습니다. |
파이썬 강제 변환 규칙 올바르게 사용하기
파이썬은 산술 연산자 및 기타 연산자를 사용해 서로 다른 값을 결합할 수 있게 해줍니다. 강제 변환 규칙은 내장 타입(예: int, float)과 사용자 정의 객체가 명시적 변환 없이도 함께 작동하도록 도와줍니다.
숫자 타입 혼합
문제: 정수와 실수를 수동 변환 없이 더하고 싶다.
해결: 파이썬은 작은 타입(int)을 큰 타입(float)으로 자동 승격시킵니다.
x = 7
y = 2.5
print(x + y)
# 9.5
파이썬은 내부적으로 7을 7.0으로 변환한 뒤 덧셈을 수행합니다.
오른쪽 덧셈(__radd__) 정의하기
문제: + 연산자의 오른쪽에 나타날 때 반응하는 클래스를 만들고 싶다.
해결: 클래스에 __radd__ 메서드를 구현합니다.
class Adder:
def __radd__(self, other):
return other + 10
a = Adder()
print(5 + a)
# 15
파이썬은 먼저 5.__add__(a)를 시도하고, 실패하면 a.__radd__(5)를 호출합니다.
두 사용자 정의 클래스 간 협력적인 이항 연산
문제: 두 사용자 정의 객체가 + 연산자를 함께 사용할 수 있어야 한다.
해결: 파이썬은 먼저 왼쪽 피연산자의 __add__를 시도하고, 실패하면 오른쪽 피연산자의 __radd__를 사용합니다.
class A:
def __add__(self, other):
return "A handles it"
class B:
def __radd__(self, other):
return "B handles it"
print(A() + B())
# A handles it
A.__add__가 성공했기 때문에 B.__radd__는 호출되지 않습니다.
%를 이용한 문자열 포맷팅
문제: 사용자 정의 포맷 로직을 작성하지 않고 % 연산자를 사용해 문자열에 값을 삽입한다.
해결책: %의 왼쪽 피연산자가 문자열이면, 파이썬은 내장 포맷 규칙을 적용한다.
name = "Ada"
print("Hello, %s!" % name)
# Hello, Ada!
% 연산자는 문자열 포맷팅 시 다른 강제 변환 메커니즘을 우회한다.
* 를 이용한 시퀀스 반복
문제: 명시적인 루프 없이 리스트나 문자열을 주어진 횟수만큼 반복한다.
해결책: 파이썬은 sequence * int 에 대해 특별한 규칙을 정의한다.
print([1, 2] * 3)
print("ha" * 2)
# [1, 2, 1, 2, 1, 2]
# haha
피연산자 중 하나가 시퀀스(list, tuple, str)이고 다른 하나가 정수이면, * 연산자는 반복을 수행한다.