파이썬 데이터 모델
데이터 모델이란?
언어 자체의 구성단위에 대한 인터페이스의 정의, 파이썬에서는 데이터 모델, 프로그래밍에서는 객체 모델이라 부른다.
특별 메서드의 개념
obj.__name__()
와 같이 메소드 중 앞 뒤로 두개의 언더바를 가지는 메서드. 인터프리터가 다양한 문맥에서 호출한다.
예: 반복, 속성 접근(obj[]), 연산자 오버로딩, …
동의어: 마술 메서드, 던더(dunder, double under) 메서드
1 |
|
장점
- 동작에 대한 임의 메서드명을 암기할 필요가 없다.
- 쉽게 동작을 위임하여 다른 기능을 추가할 수 있다.
helloworld[1::-1]
(__getitem__
)for item in HelloWorld: ...
(__len__
,__getitem__
)
- 표준 라이브러리와 연계가 쉽다. 예:
choice(helloworld)
한 특별 메서드의 기능이 다른 메서드에 위임되기도 한다.
예: __contains__
메서드가 없으면 선형 탐색을 통해 찾아본다.
1 |
|
여기서 in 은 다음과 같은 선형 탐색을 한다.
1 |
|
그러나 __init__
를 제외한 특별 메서드는 직접 호출하지 않는것이 좋다. 내부적으로 특별 메서드 보다 빠른 방식이 있다면 빠른 방식을 택하기 떄문.
len(data)의 경우 내장 데이터 형의 경우 특별 메서드를 호출하지 않기도 하며, 이 경우 바이너리로 필드를 읽어 훨신 더 빠르다. 따라서 len과 같은 함수들은 메서드가 아니라 함수여야한다.
결론
- 특별 메서드를 지원하여 다양하게 활용할 수 있도록 하자
- 던더 메서드는(
__f__
) 특별 메서드이므로 일반 함수에서는 저런 꼴의 이름을 작성하지 말자. - 특별 메서드는 간접적으로 호출하자
개인 메모
- 특별 메서드를 지원하면 가능해지는 연산을 꼭 확인하자. 의도치 않게 위임을 통해 지원하게 되면, O(1)로 가능한 연산도 O(n)으로 지원하게 되어 구현을 깜빡할 수 있다.
개인적으로 정리
이항 산술 연산자
표현식 | 특별 메서드 |
---|---|
a+b |
a.__add__(b) |
a-b |
a.__sub__(b) |
a*b |
a.__mul__(b) |
a/b |
a.__truediv__(b) |
a//b |
a.__floordiv__(b) |
a%b |
a.__mod__(b) |
a**b |
a.__pow__(b) |
a<<b |
a.__lshift__(b) |
a>>b |
a.__rshift__(b) |
a&b |
a.__and__(b) |
a^b |
a.__xor__(b) |
a|b |
a.__or__(b) |
앞에 r을 붙이면 a,b가 바뀐다
예: a+b
에서 a.__add__
가 없을 경우 b.__radd__(a)
앞에 i를 붙이면 산술 대입 연산자가 된다
예: a+=b
에서 a.__iadd__(b)
단항 산술 연산자
표현식 | 특별 메서드 |
---|---|
-a |
a.__neg__() |
+a |
a.__pos__() |
~a |
a.__invert__() |
f(a)
가 a.__f__
인 예
divmod, pow, abs, complex, int, float, round, trunc, floor, ceil, hash, len, length_hint, repr, ...
접근 연산자
표현식 | 특별 메서드 |
---|---|
a[b:c:] |
a.__getitem__(slice(b,c,None)) |
a[b] |
a.__getitem__(b) |
a[b] = c |
a.__setitem__(b,c) |
호출 연산자
표현식 | 특별 메서드 |
---|---|
a(b,c,...) |
a.__call__(b,c,...) |
문자열화 연산자
표현식 | 특별 메서드 |
---|---|
print(a) |
print(str(a)) |
str.format(a,...) |
str.format(str(a)),...) |
a.__repr__() |
'<a에 대한 설명>' 혹은 '같은 a를 생성할 수 있는 표현식' |
위임 되는 예
표현식 | 특별 메서드 |
---|---|
reversed(a) |
__reversed__ , 없으면 __len__, __getitem__ |
b in a |
__contains__ , 없으면 __iter__ , 없으면 __getitem__ |
bool(a) |
__bool__ , 없으면 __len__() != 0 , 없으면 return True |
str(a) |
__str__ , 없으면 __repr__() |
복합 할당의 경우(본문 2.6)
1 |
|
는 다음과 같다
1 |
|
- 복합 할당일때는 원자적인 연산이 아니다.
- a가 불변 시퀀스일 경우,
__iadd__
의 실행 후__setitem__
이 호출되므로, iadd는 성공했으나 setitem에서 오류가 발생한다. 이때 a의 엘리먼트는 iadd되었으므로 예외는 발생했으나 add는 정상적인 요상한 상황을 만든다. 따라서 가변 항목을 불변 시퀀스에 넣는건 좋은 생각이 아니다.