[Fluent Python] 9장 파이썬스러운 객체

파이썬스러운 객체

절대로 결코 앞에 언더바 두 개를 사용하지 말라. 이것은 짜증스러울 정도로 개인적인 이름이다. - 이안 비킹. Paste 스타일 가이드에서 발췌

객체의 표현

repr()는 개발자가 보고자 하는 형태로 표현한 문자열, str()은 사용자가 보고자 하는 형태로 표현한 문자열을 반환한다.

벡터 클래스의 구현

깃헙 페이지를 참고하자.

byte() 함수로 저장하고, memoryview()cast()로 로딩이 가능하다.

@classmethod와 @staticmethod

이 두 데커레이터는 self를 생략하게 만드는데, 전자는 해당 클래스를 첫 인자로 받게 만들어주고, 후자는 첫번째 인자를 무시하게끔 만든다.

포멧된 출력

내장함수인 format()과 메서드인 str.format()를 이용한다. format에서 이용되는 형식을 포맷 명시 간이 언어(Format Specification Mini-Language)라고 부른다.

해시 가능한 Vector2D

지금까지 정의한 Vector2D는 해시할 수 없으므로, 집합에 쓸 수 없다. 해시 가능하게 하려면 __hash()__를 구현해야 한다. 해시 가능하게 하려면 우선 불변형으로 만들어야 한다.

@property 데커레이터를 통해서 변수의 직접 접근을 막고, 읽기 전용으로 만든다. 불변형이 된 상태에서 해시 함수를 구현해야 한다. 해시 함수는 반드시 int 형을 반환해야 한다. 동일한 객체는 동일한 해시를 가져야 하므로, __eq()__ 함수에서 이용한 특성을 이용해서 구현하는 것이 좋다. 공식 문서에는 요소의 해시에 비트 단위 XOR 연산자 (^)를 사용하는 것을 권장한다. Vector2D는 다음과 같이 구현할 수 있다.

def __hash__(self):
    return hash(self.x) ^ hash(self.y)

파이썬에서의 비공개 속성과 보호된 속성

파이썬에서는 클래스의 상속 과정에서 변수명이 중복되는 것을 방지하기 위해서 이름 장식(name mangling)이라고 하는 방식을 도입하였다. 변수명앞에 클래스명을 추가로 붙여준다. 하지만 이는 보안 기능은 아니다. 실수를 방지하지만 고의적인 악용을 막지는 못한다. 이안 비킹은 이와 관련하여 언더바 두개(던더, dunder)를 쓰지 말것을 주장하면서, 차라리 던더 대신 언더바+클래스명+언더명을 쓰라고 주장한다. 이 또한 나쁘지만 최소한 의도가 명확하게 보이기 때문이다.

파이썬에서는 관례적으로 언더바 1개는 보호된 속성이라고 생각하고 사용하는 측면에서 의도적으로 사용하지 않으려고 하는 관례가 있지만, 강제적으로 규정할 수는 없다.

__slots___ 클래스 속성으로 공간 절약하기

파이썬은 기본적으로 객체 속성을 각 객체 안의 __dict__라는 딕셔너리형 속성에 저장한다. 이는 빠르게 속성에 접근할 수 있게 하지만, 메모리 사용량 부담이 커지게 된다. 이 때 __slots__ 클래스 속성을 이용하면 딕셔너리 대신 튜플에 저장하게 만듦으로써 메모리 사용량을 엄청나게 줄일 수 있다.

숫자 데이터를 처리하는 경우는 NumPy를 사용하자.

class Vector2d:
    __slots__ = ('__x', '__y')
    typecode = 'd'

위 코드와 같이 작성하면, 인터프리터가 해당 속성을 튜플형 구조체에 저장한다.

$ time python3 mem_test.py vector2d_v3.py
$ time python3 mem_test.py vector2d_slots.py

저장소의 코드를 이용하여, 위 명령으로 실행할 수 있다.

메모리 사용량을 체크하는 아래 코드는 인상적이다.

mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss

__slots__를 이용하게 되면, 클래스에 속성을 추가할 수 없게 되는데, 이는 최적화를 위한 희생이다. 이러한 방법을 클래스 확장을 막는 기능으로 사용하면 안된다.

어설픈 최적화는 독이 되기 마련이므로, 수치형 자료를 다룰 때는 NumPy를, 비수치형 자료를 다룰 때는 pandas를 이용하자.

__slots__ 사용시 유의점

클래스 속성 오버라이드

파이썬은 클래스 속성을 객체 속성의 기본값으로 사용하는 특징이 있다.

__bytes__() 메서드에서 사용예를 살펴보았는데, self.typecode는 기본적으로 Vector2d.typecode 클래스 속성을 가져온다.

읽을거리

객체를 두 가지 문자열로 출력할 필요에 대한 초기 인식은 스몰토크에서 나타났다. 바비 울프(Bobby Woolf)의 1992년 논문 “객체를 문자열로 출력하는 방법: printString()과 displayString() 메서드”에서 설명하고 있다.

자바의 접근 지시자 역시 안전 장치이다. 보안 장치가 아니다. 보안 관리자와 함께 배포하지 않으면, 바이트 코드를 읽어서 쉽게 해당 필드를 읽을 수 있다.