코드를 작성할 때, 동일한 구조를 반복하고 따르게 되는 게 보통이다.
이걸 관용구(idiom)이라 부른다.
디자인 패턴과는 다르다.
디자인 패턴은 프로그래밍 언어와 무관한
개념으로, 그 개념 자체로 코드로 변환되지 않는다.
반면, 관용구(idiom)는 그 자체가 코드로 즉시 변환된다.
또한, 관용구는 프로그래밍 언어에 따라 다르므로 각 커뮤니티마다 지향하는 스타일이 생기기 마련이다.
파이썬에서는 파이썬스러운 관용구를 파이썬스럽다(Pythonic)라고 부른다.
파이썬스러운 코드는 보통 더 나은 성능을 내고, 직관적으로 이해할 수 있다. 그리고 전체 개발팀이 동일한 패턴과 구조를 사용하게 됨으로써, 실수를 줄이고 문제의 본질에 집중할 수 있게 된다.
slice(시작, 중지, 간격)
>>> my_nums = (4, 5, 3, 9)
>>> my_nums[-1]
9
>>> my_nums[-3]
5
>>> fibo_nums = (1, 1, 2, 3, 5, 8, 13, 21, 34)
>>> fibo_nums[:3]
(1, 1, 2)
>>> fibo_nums[3:]
(3, 5, 8, 13, 21, 34)
>>> fibo_nums[::]
(1, 1, 2, 3, 5, 8, 13, 21, 34)
>>> fibo_nums[1:7:2]
(1, 3, 8)
# 재밌는 점
>>> fibo_nums[1:999999:2]
(1, 3, 8, 21)
위의 기능들은 __getitem__
매직 메서드 덕분에 작동한다.
객체[key]
를 사용하면 key에 해당되는 값을 파라미터로 전달한다.
특히 시퀀스는 __getitem__
과 `__len__
을 모두 구현하는 객체이므로 반복이 가능하다.
업무 도메인에서 사용하는 사용자저의 클래스에 __getitem__
을 구현할 때 pythonic하게 작성하려면 어떻게 해야할까?
(래퍼 또는 상속사용 방식이 아닌 자체 구현할 경우)
# __getitem__, __len__ 매직메서드가 있음을 알 수 있다
>>> dir(fibo_nums)
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
>>>
리스트의 일부를 slice한 결과는 리스트다.
튜플에서 특정 range를 호출하면 그 결과를 튜플이다.
substring한 문자열의 결과는 substring이다.
ex) >>> my_str = "Harry Potter"
>>> my_str[6:]
'Potter'
이건 일관성에 관한 이야기다.
파이썬의 자체 slice 기능은 마지막 인덱스를 제외한 동일 객체 타입을 리턴한다.
하지만 커스텀 클래스(사용자정의 클래스)에서의 시퀀스 거동이
파이썬의 그것과 다르다면 다른 개발자와 어떻게 일을 할 수 있겠는가