EXCELSIOR

01 - 파이썬 데이터 모델 본문

Python/Fluent Python

01 - 파이썬 데이터 모델

Excelsior-JH 2018. 2. 22. 15:43

Chapter01 - 파이썬 데이터 모델

데이터 모델은 일종의 프레임워크로서, 파이썬을 설명하는 것 이라고 할 수 있으며, 시퀀스(sequences), 반복자(iterators), 함수(functions), 클래스(class), 콘텍스트 관리자 등 언어 자체의 구성단위에 대한 인터페이스를 공식적으로 정의한다. 파이썬은 매직 메소드(특별 메소드, magic method) 를 호출해서 기본적인 객체 연산을 수행한다. 매직 메소드는 __getitem__() 처럼 이중 언더바를 가지고 있다. 예를 들어, obj[key]형태의 구문은 __getitem__() 매직 메소드가 지원한다. __getitem__()과 같은 메소드를 읽을때에는 던더(dunder) - getitem이라고 부르는 것을 선호한다고 한다. 던더는 더블 언더바(double under)를 줄인 말이다. 따라서, 매직 메소드를 던더 메소드 라고도 한다.

1.1 파이썬 카드 한 벌

아래의 [예제 1-1]은 간단한 코드지만, 매직 메서드 __getitem__()__len__()만으로도 괜찮은 기능을 구현할 수 있다는 것을 보여준 예시이다. 이 코드는 카드(스페이드, 다이아몬드, 클로버, 하트) 한 벌을 나타내는 클래스FrenchDeck 이다.

 


[예제 1-1] 코드는 collections.namedtuple() 을 이용해서 구현 하였다. collections.namedtuple()에 대해서는 여기를 참고하면 된다. FrenchDeck 클래스는 __len__ 메소드를 정의해 줌으로써 len() 함수를 통해 카드의 수를 반환 한다.

 


또한, __getitem__ 정의를 통해, obj[key] 형태로 특정 카드를 읽을 수 있다. 예를 들어, deck[0]은 첫 번째 카드 이며, deck[-1]은 마지막 카드를 가져온다.

 


이렇듯, 매직 메소드를 통해 파이썬 데이터 모델을 사용할 때의 두 가지 장점이 있다.

  • 사용자가 표준 연산을 수행하기 위해 클래스 자체에서 구현한 임의 메서드명을 암기할 필요가 없다.

  • 파이썬 표준 라이브러리에서 제공하는 기능을 별도로 구현할 필요 없이 바로 사용할 수 있다.

__getitem__() 메소드는 self._cards를 호출 하므로, 슬라이싱(slicing)도 당연히 지원한다.

 

__getitem__() 매직 메소드를 구현함으로써 deck을 리스트 형태 처럼 반복할 수도 있다.

 


이 외에도 in 이나 정렬(sort)를 적용할 수도 있다. 교재에서는 정렬을 카드 (에이스가 제일 높고, 숫자가 같은 경우 스페이드 > 하트 > 다이아몬드 > 클로버 순) 순으로 정렬하는 코드를 아래와 같이 작성 했다.

 

FrenchDeck 클래스에 __len__()__getitem__() 매직 메소드를 구현함으로써 FrenchDeck은 마치 파이썬 시퀀스(ex. list) 처럼 작동하므로 반복, 슬라이싱 등이 가능하다.


1.2 매직 메서드는 어떻게 사용되나?

파이썬 코드는 my_object.__len__()으로 직접 호출하지 않고, len(my_object) 형태로 호출한다. list, str, bytearray 등과 같은 내장(built-in) 자료형의 경우 파이썬은 위와 같은 형태로 호출한다. 매직 메소드는 종종 암묵적으로 호출된다. 예를 들어, for i in x: 문의 경우 실제로는 iter(x)를 호출하며, 이 함수는 다시 x.__iter__()를 호출한다. 매직 메소드를 호출해야 하는 경우, 일반적으로 len(), iter(), str() 등 내장함수(built-in function)을 호출하는 것이 좋다. 이러한 내장 함수가 해당 매직 메소드를 호출하기 때문이다.

그렇다면, 각 클래스의 매직 메소드를 어떻게 확인할까? 각 클래스의 매직 메소드는 dir(MyClass)를 이용해서 해당 클래스의 매직 메소드를 확인할 수 있다. 아래의 코드는 매직 메소드를 확인하는 코드이다. 매직 메소드에 대해서는 docs.python.org 에서 확인할 수 있다.

 


1.2.1 수치형 흉내 내기

아래의 그림과 같이 2차원 벡터를 나타내는 클래스를 구현해 매직 메소드를 사용하는 방법을 알아보도록 하자.


[예제 1-2]는 __repr__(), __abs__(), __add__(), __mul__() 매직 메소드를 이용해서 Vector 클래스를 구현한 코드이다.

 

 


1.2.2 문자열 표현

__repr__() 매직 메소드는 객체를 문자열로 표현하기 위해 repr() 내장 함수에 의해 호출된다. 만약 __repr__()을 구현하지 않으면 Vector 클래스의 객체는 <__main__.Vector at 0x255c338c550> 이러한 형태로 출력이 된다. (위의 Vector 클래스에서 __repr__()을 지우고 실행하면 됨)

 


이번에는 __repr__()과 비슷한 역할을 하는 __str__()을 비교해보자. __str__() 메소더는 str() 에 의해 호출되며 print() 함수에 의해 암묵적으로 사용된다. 즉, print()를 호출해야지 __repr__()과 같은 기능을 한다는 으미이다. 따라서, 두 매직 메소드 중 __repr__()을 구현하는게 좋다고 한다. 그 이유는 파이썬에서 __str__() 메소드가 구현되어 있지 않을 때 대책으로 __repr__() 메소드를 호출하기 때문이다. 아래의 Vector2 클래스는 __repr__() 대신 __str__() 매직 메소드를 사용한 클래스이다. 이 클래스를 이용해서 객체를 만들면, print()를 호출할때 문자열로 출력되는 것을 확인할 수 있다.

 

 


1.2.3 생략


1.2.4 사용자 정의형의 불리언 값

파이썬에서 어떠한 객체 x인지 거짓인지 판단하는 방법은 bool(x) 를 사용하며, 이 bool() 함수는 True, False를 반환한다.

__bool__()이나 __len__()을 구현하지 않은 경우, 파이썬은 기본적으로 사용자가 정의한 클래스의 객체는 참(True)이라고 간주한다. bool(x)x.__bool__()을 호출하며, __bool__()이 구현되어 있지 않으면, x.__len__()을 호출하며, 이 매직 메소드가 0을 반환하면 bool()False를 그렇지 않으면 True를 반환한다.

위의 [예제 1-2]의 Vector클래스에서의 __bool__()은 벡터의 크기(abs(self))가 0이면 False 를 반환하고, 그렇지 않으면 True를 반환한다.

 


1.3 매직 메소드 개요

파이썬 언어 참조 문서의 'Data Model'에서는 83개의 매직 메소드를 설명하고 있다.

범주메소드 명
문자열/바이트표현__repr__, __str__, __format__, __bytes__
숫자로 변환__abs__, __bool__, __complex__, __int__, __float__, __hash__, __index__
컬렉션 에뮬레이션__len__, __getitem__, __setitem__, __delitem__, __contains__
반복__iter__, __reserved__, __next__
콜러블 에뮬레이션__call__
콘텍스트 관리__enter__, __exit__
객체 생성 및 소멸__new__, __init__, __del__
속성 관리__getattr__, __getattribute__, __setattr__, __delattr__, __dir__
속성 디스크립터__get__, __set__, __delete__
클래스 서비스__prepare__, __instancecheck__ __subclasscheck__
단항 수치 연산자__neg__ -, __pos__ +, __abs__ abs()
향상된 비교 연산자__lt__ >, __le__ <=, __eq__ ==, __ne__ !=, __gt__ >, __ge__ >=

산술 연산자

__add__ +, __sub__ -, __mul__ *, __truediv__ /, __floordiv__ //, __mod__
역순 산술 연산자__radd__, __rsub__, __rmul__, __rtruediv__, __rfloordiv__, __rmod__, __rdivmod__, __rpow__
복합 할당 산술 연산자__iadd__, __isub__, __imul__, __itruediv__, __ifloordiv__, __imod__, __ipow__
비트 연산자__invert__ ~, __lshift__ <<, __rshift__ >>, __and__ &, __or__ |,__xor__ ^
역순 비트 연산자__rlshift__, __rrshift__, __rand__, __rxor__, __ror__
복합 할당 비트 연산자__ilshift__, __irshift__, __iand__, __ixor__, __ior__


1.4 생략


1.5 요약

매직 메소드를 구현하면 사용자가 정의한 클래스의 객체도 내장형 객체처럼 작동할 수 있어, 파이썬 스러운(Pythonic) 코딩 스타일을 구사할 수 있다.

'Python > Fluent Python' 카테고리의 다른 글

02 - 시퀀스 Sequence  (0) 2018.08.05
Comments