Effective Python: 좋은 파이썬 코드를 작성하는 125가지 방법
좋은 파이썬 코드를 작성하는 125가지 방법
1. Pythonic Thinking
Item 1: 어떤 파이썬 버전을 쓰는지 알아라
- 신규 프로젝트는
Python 3를 사용해라. - 커맨드라인에서 실행하는
python/python3가 “네가 의도한 파이썬(가상환경)”인지, “시스템 파이썬”인지부터 확인해라. Python 2는 공식적으로 코어 개발자들에게 더이상 메인테인 받지 않는다.
Item 2: PEP 8 스타일 가이드를 따라라
- 파이썬 코드를 작성할 때는 항상
PEP 8을 따라라. - 공통 스타일을 공유하면 파이썬 커뮤니티/팀에서 협업이 쉬워진다.
- 일관된 스타일을 유지해서 코드를 수정하기 쉽게 만들어라.
Black그리고pylint같은 커뮤니티 툴로PEP 8준수를 자동화해라.
Item 3: 파이썬이 항상 컴파일 할때 에러를 감지할거라고 기대하지 마라
- 파이썬은 에러 체크 대부분을
runtime으로 미룬다. - 실행하기 전에는 “당연히 잡힐 것 같은 실수”도 안 잡힐 수 있다고 생각해라.
linter와static analysis로 흔한 에러를 실행 전에 잡아라.
Item 4: 복잡한 표현(코드) 대신 helper function을 작성해라
- 한 줄로 억지로 우겨 넣어서 너무 복잡하게 만들지 마라.
- 복잡한
expression은helper function으로 빼라. - 특히 그 로직을 반복해서 쓸 거면 확실하게 함수로 옮겨라.
Item 5: indexing 말고 unpacking을 선호해라
- 시퀀스를
index로 덕지덕지 접근하지 마라. - 가능한 곳에서는
unpacking으로 여러 값을 한 번에 받아라. unpacking으로 시각적 잡음을 줄이고 가독성을 올려라.
Item 6: 항상 single-element tuple은 괄호로 감싸라
tuple리터럴은 보통 괄호가 optional 이고, trailing comma도 케이스에 따라 들어간다.- single-element
tuple은 원소 뒤에 trailing comma가 필수다. 괄호는 있어도 되고 없어도 된다. - 표현식 끝에 실수로 trailing comma를 붙이면 의미가 single-element
tuple로 바뀐다. 프로그램을 깨먹을 수 있으니 조심해라.
Item 7: 간단한 inline 로직이면 conditional expression을 고려해라
- 파이썬은
if를 표현식 자리에도 넣을 수 있게conditional expression을 제공한다. conditional expression은 다른 언어의 삼항연산자랑 순서가 다르다. 헷갈리지 않게 조심해라.- 애매해지거나 처음 보는 사람이 읽기 어려워지면 쓰지 마라.
- 이득이 확실하지 않으면 일반
if문이랑helper function을 써라.
Item 8: assignment expression으로 반복을 막아라
assignment expression은 walrus operator:=로 “할당 + 평가”를 한 번에 한다. 반복을 줄여라.- 큰 표현식 안의 subexpression으로 쓰면 괄호로 감싸라.
- 파이썬에
switch/case나do/while은 없지만, 이런 패턴 일부는assignment expression으로 더 명확하게 흉내낼 수 있다.
Item 9: 흐름 제어에서 구조 분해가 필요하면 match를 고려해라. if로 충분하면 쓰지 마라
- 단순
if를match로 억지로 바꾸지 마라. 실수하기 쉽고 직관적이지 않은 함정이 있다. match는isinstance체크 + destructuring을 flow control과 같이 묶어야 할 때 강하다. heterogeneous object graph나 semi-structured data 해석할 때 써라.case pattern은list/tuple/dict같은 built-in 구조랑 사용자 정의 클래스에 쓸 수 있다. 근데 타입마다 semantics가 다르다. 바로 안 보이면 함부로 쓰지 마라.
2. Strings and Slicing
Item 10: bytes 와 str의 차이를 알아라
bytes는 8-bit 값의 시퀀스고,str은 유니코드 코드 포인트의 시퀀스다.- 네가 다루는 입력이 어떤 문자 시퀀스 타입인지 보장하려면
helper function을 써라. bytes와str은 같이 섞어서 연산하지 마라(예:>,==,+,%). 애초에 같이 못 쓰는 경우가 많다.- 파일에 binary 데이터를 읽고/쓸 때는 항상 바이너리 모드로 열어라(예:
"rb","wb"). - 파일에 유니코드 텍스트를 읽고/쓸 때는 시스템 기본 인코딩을 믿지 마라.
open에encoding=...을 명시해라.
Item 11: C-style % / str.format 말고 f-string을 써라
%포맷팅은 gotcha도 많고 장황하다. 쓰지 마라.str.format은 포맷 스펙 미니-언어 같은 유용한 개념은 있지만, 결국%의 실수를 반복한다. 피하는 게 낫다.f-string은 문자열에 값을 넣는 최신 문법이고,%방식의 큰 문제를 해결한다.f-string은 짧고 강력하다. 포맷 스펙 안에 임의의 파이썬expression을 바로 넣을 수 있다.
Item 12: 객체 출력할 때 repr vs str 차이를 알아라
- built-in 타입에
print를 호출하면 사람이 읽기 쉬운 문자열(str)이 나온다. 타입 정보 같은 건 숨겨질 수 있다. - built-in 타입에
repr를 호출하면 “출력 가능한 표현”이 나온다. 경우에 따라repr문자열은eval로 다시 원래 값으로 복구될 수도 있다. - 포맷 문자열에서
%s는str처럼 사람이 읽기 쉬운 문자열을 만든다.%r은repr처럼 출력 가능한 표현을 만든다.f-string은 기본이str이고,!r을 붙이면repr로 바뀐다. - 커스텀 클래스는
__repr__과__str__을 정의해라. 디버깅이 쉬워지고, 사람 대상 UI/로그에 객체를 붙이기도 편해진다.
Item 13: 리스트에서는 암시적 문자열 결합 말고 명시적으로 붙여라
- 파이썬은 문자열 리터럴 두 개가 코드에서 붙어 있으면
+가 있는 것처럼 자동으로 합친다(C 언어 스타일과 비슷하다). list/tuple리터럴 안에서는 암시적 결합을 피하라. 작성자 의도가 애매해져서 읽는 사람이 헷갈린다.+로 명시적으로 붙여라.- 함수 호출에서는 positional argument가 1개이고 keyword argument만 추가되는 형태라면 암시적 결합을 써도 괜찮다.
- positional argument가 여러 개라면 암시적 결합을 쓰지 마라.
+로 명시적으로 붙여라.
Item 14: 시퀀스 슬라이싱을 제대로 알아라
- 슬라이싱을 쓸 때 불필요하게 장황하게 쓰지 마라. 시작 인덱스에
0을 넣거나, 끝 인덱스에 시퀀스 길이를 넣지 마라. - 슬라이싱은 범위를 넘어가는 인덱스에 관대하다. 앞/뒤 경계 슬라이스를 쉽게 표현해라(예:
a[:20],a[-20:]). list슬라이스에 값을 할당하면 원본 시퀀스의 해당 구간이 통째로 교체된다. 길이가 달라도 그대로 치환된다.
Item 15: 한 표현식에서 striding과 slicing을 같이 쓰지 마라
- 시작/끝/stride를 한 번에 지정하는 슬라이스는 읽기 어렵고 혼란스럽다.
- stride가 필요하면 start/end 없이 양수의 stride만 쓰는 쪽을 선호해라. 음수 stride는 가능하면 피하라.
- start/end/stride를 한 번에 써야 한다면 두 단계로 나눠라(먼저 stride로 뽑고, 그 다음 slice로 자르기). 아니면
itertools의islice를 써라.
Item 16: slicing보다 catch-all unpacking을 선호해라
unpacking에는 starred expression을 넣을 수 있다. 남는 값들을 한 번에list로 받아라.- starred expression은 패턴 어디에나 둘 수 있다. 결과는 항상 0개 이상 값을 담는
list가 된다. - 리스트를 겹치지 않는 조각으로 나눌 때는, slicing과 indexing을 여러 줄로 쓰지 마라. catch-all
unpacking이 더 덜 위험하고 실수도 줄어든다.
3. Loops 그리고 Iterators
Item 17: range 말고 enumerate를 써라
enumerate는 이터레이터를 돌면서 각 아이템의 인덱스를 같이 받는 문법을 간결하게 제공한다.range로 루프 돌리고 시퀀스를index로 찍는 방식 대신enumerate를 써라.enumerate는 두 번째 인자로 시작 카운트를 지정할 수 있다(기본은0이다).
Item 18: 이터레이터를 병렬로 처리하려면 zip을 써라
zip은 여러 이터레이터를 병렬로 순회할 때 써라.zip은 튜플을 만들어내는 lazy generator다. 무한 입력에도 쓸 수 있다.- 길이가 다른 이터레이터를 넣으면 가장 짧은 쪽에 맞춰서 조용히 잘린다.
- 조용히 잘리는 걸 막고 싶으면
zip에strict=True를 넘겨라. 길이가 다르면runtime에러로 터지게 해라.
Item 19: for/while 뒤에 붙는 else 블록은 피하라
- 파이썬은
for/while바로 뒤에else블록을 붙일 수 있는 특수 문법이 있다. - 루프 뒤
else는 루프 바디가break를 만나지 않았을 때만 실행된다. - 루프 뒤
else는 직관적이지 않다. 헷갈리니까 쓰지 마라.
Item 20: 루프가 끝난 뒤 for 변수는 절대 쓰지 마라
for루프 변수는 루프가 끝나도 현재 스코프에서 접근 가능하다. 그거 믿고 쓰지 마라.- 루프가 한 번도 돌지 않으면
for변수는 스코프에 할당조차 안 될 수 있다. generator expression이랑list comprehension은 기본적으로 루프 변수를 밖으로 새지 않게 만든다.exception handler도 예외 인스턴스 변수를 밖으로 새지 않게 한다.
Item 21: 인자 이터레이션은 방어적으로 해라
- 함수/메서드가 입력 인자를 여러 번 순회하는지 조심해라. 인자가
iterator면 값이 사라지거나 이상한 동작이 난다. - 파이썬
iterator protocol이iter/next와for루프 같은 동작을 어떻게 연결하는지 이해해라. - 너만의 iterable 컨테이너가 필요하면
__iter__를 generator로 구현해라. - 값이
iterator인지 확인하려면iter(x) is x패턴을 써라(같은 객체가 나오면 iterator일 가능성이 크다). 또는isinstance(x, collections.abc.Iterator)로 판별해라.
Item 22: 순회 중에는 컨테이너를 절대 수정하지 마라. 대신 복사본이나 캐시를 써라
list/dict/set을 순회하면서 요소를 추가/삭제하지 마라. 예측하기 어려운runtime에러나 버그가 난다.- 수정이 필요하면 컨테이너의 복사본을 순회해라.
- 성능 때문에 복사를 피해야 하면, 변경 사항을 두 번째 컨테이너(캐시)에 모아뒀다가 나중에 원본에 합쳐라.
Item 23: 효율적인 short-circuit 로직엔 any와 all에 이터레이터를 넘겨라
all은 모든 항목이 truthy면True를 반환한다. falsey를 만나면 즉시 멈추고False를 반환한다.any는 반대로 동작한다. 모든 항목이 falsey면False고, truthy를 만나면 즉시 멈추고True를 반환한다.any/all은 항상True또는False만 반환한다.and/or처럼 “마지막으로 평가된 값”을 반환하지 않는다.any/all에list comprehension을 쓰지 마라.generator expression을 써서 short-circuit 이점을 살려라.
Item 24: 이터레이터/제너레이터 작업엔 itertools를 고려해라
itertools는 이터레이터/제너레이터를 다룰 때 쓰는 표준 도구 모음이다.- 큰 분류는 3가지로 생각해라: 이터레이터 연결, 출력 필터링, 조합 생성.
- 더 고급 함수, 파라미터, 유용한 레시피는 공식 문서를 참고해라.
4. Dictionaries
Item 25: dict 삽입 순서(insertion ordering)에 의존할 땐 조심해라
Python 3.7부터dict를 순회하면 키가 처음 추가된 순서대로 나온다고 기대해도 된다.- 하지만
dict처럼 동작하는 “딕셔너리 비슷한 타입”은dict인스턴스가 아닐 수 있다. 이런 타입은 삽입 순서를 보장한다고 가정하지 마라. -
딕셔너리 같은 클래스에 안전하게 대응하려면 셋 중 하나로 가라.
- 삽입 순서에 의존하지 않는 코드로 짜라.
- 런타임에
dict타입인지 명시적으로 검사해라. - 타입 힌트와
static analysis로 입력을dict로 강제해라.
Item 26: 키가 없을 때는 in/KeyError 말고 get을 우선 써라
- 딕셔너리에서 missing key를 처리하는 흔한 방법은 4개다:
in,KeyError,get,setdefault. - 기본 타입(카운터 같은 것) 다룰 때는
get이 제일 무난하고 깔끔하다. - 기본값 생성 비용이 크거나 예외가 날 수 있으면
get을 쓰고, 필요하면assignment expression으로 중복을 줄여라. setdefault가 좋아 보이면defaultdict가 더 맞는지 먼저 검토해라.
Item 27: 내부 상태 관리에는 setdefault 말고 defaultdict를 써라
- 가능한 키가 계속 늘어날 수 있는 내부 상태용 딕셔너리를 만든다면
collections.defaultdict를 우선 고려해라. - 딕셔너리가 외부에서 들어오는 값이라 네가 생성 과정을 컨트롤 못 하면, 접근은 기본적으로
get으로 해라. - 그래도 코드가 확 짧아지고 기본값 생성 비용이 낮은 일부 상황에서는
setdefault를 써도 된다.
Item 28: 키에 따라 기본값이 달라져야 하면 __missing__을 써라
- 기본값 생성 비용이 크거나 예외가 날 수 있으면
dict.setdefault는 나쁜 선택이다. defaultdict의 factory 함수는 인자를 받을 수 없다. 그래서 “키에 의존하는 기본값”을 만들 수 없다.- 키에 따라 기본값을 만들어야 하면
dict를 상속하고__missing__을 정의해서 처리해라.
Item 29: 딕셔너리/리스트/튜플을 깊게 중첩하지 말고 클래스를 조합해라
- 값이 또 딕셔너리인 딕셔너리, 긴 튜플, 복잡하게 중첩된 built-in 타입 덩어리를 만들지 마라.
- 완전한 클래스가 필요해지기 전까지는 가벼운 데이터 컨테이너로
dataclasses를 먼저 써라. - 내부 상태용 딕셔너리가 복잡해지기 시작하면 bookkeeping 코드를 여러 클래스로 쪼개서 관리해라.
5. Functions
Item 30: 함수 인자는 변형될 수 있다는 걸 알아라
- 파이썬 인자는 reference로 전달된다. 함수/메서드가 인자의 attribute나 내부 값을 바꿀 수 있다.
- 입력을 수정할 거면 이름이랑 문서로 “수정한다”는 걸 분명히 드러내라. 아니면 수정하지 마라.
- 실수로 원본을 건드리기 싫으면, 받은 컬렉션/객체를 복사해서 써라.
Item 31: 3개 초과 언패킹 강요하지 말고 전용 결과 객체를 반환해라
- 함수는 튜플로 여러 값을 반환하고, 호출자는
unpacking으로 받을 수 있다. - catch-all starred expression으로 여러 반환값을 받을 수도 있다.
- 4개 이상 변수로 언패킹하게 만들지 마라. 실수하기 쉽다. 대신 가벼운 클래스 인스턴스를 반환해라.
Item 32: None 반환하지 말고 예외를 던져라
- 특별한 의미로
None을 반환하게 만들지 마라.None은Boolean에서 falsey라서0이나""같은 값이랑 섞이면 버그 난다. - 특수 상황은
None이 아니라 예외로 표현해라. 문서화하고 호출자가 예외를 처리하게 만들어라. - 타입 힌트로 “이 함수는 어떤 경우에도
None을 반환하지 않는다”를 명확히 해라.
Item 33: 클로저 스코프랑 nonlocal을 제대로 알아라
- 클로저 함수는 자신을 감싸는 스코프의 변수를 참조할 수 있다.
- 기본적으로 클로저는 바깥 스코프 변수에 “할당”해서 영향을 주지 못한다.
- 바깥 스코프 변수를 수정해야 하면
nonlocal을 써라. 모듈 레벨 이름을 수정해야 하면global을 써라. nonlocal은 단순한 경우 외에는 남발하지 마라. 복잡해지면 코드가 읽기 어려워진다.
Item 34: 가변 위치 인자로 visual noise를 줄여라
- 함수가 위치 인자를 여러 개 받게 하려면 정의에서
*args를 써라. - 시퀀스의 아이템을 위치 인자로 풀어서 넘기려면 호출에서
*를 써라. - generator에
*를 바로 쓰지 마라. 메모리를 과하게 잡아먹어서 터질 수 있다. *args받는 함수에 새 위치 인자를 추가하지 마라. 호출자 쪽 버그가 조용히 생기기 쉽다.
Item 35: keyword 인자로 옵션 동작을 제공해라
- 함수 인자는 position으로도, keyword로도 넘길 수 있다.
- 위치 인자만 쓰면 의도가 헷갈리는 곳은 keyword로 명확히 해라.
- 기본값 있는 keyword 인자는 기존 호출자를 다 안 고치고도 새 동작을 추가할 수 있게 해준다.
- optional keyword 인자는 항상 keyword로 넘겨라. position으로 넘기지 마라.
Item 36: 동적인 기본값은 None과 docstring으로 지정해라
- 기본 인자 값은 함수 정의 시점(모듈 로드 시점)에 한 번만 평가된다. 동적인 값(함수 호출, 새 객체, 컨테이너)은 이상한 버그를 만든다.
- 동적으로 초기화돼야 하는 기본값은 placeholder로
None을 써라. 실제 기본값 의도는 docstring에 적어라. 함수 바디에서None체크해서 올바른 기본 동작을 트리거해라. Noneplaceholder 방식은 타입 힌트랑 같이 써도 깔끔하게 맞는다.
Item 37: keyword-only / positional-only 인자로 호출 의도를 강제해라
- keyword-only 인자는 특정 인자를 반드시 keyword로 넘기게 만들어서 호출 의도를 명확하게 한다. 인자 리스트에서
*뒤에 둬라(*단독이든*args든 상관없다). - positional-only 인자는 특정 파라미터를 keyword로 못 넘기게 해서 결합도를 줄인다. 인자 리스트에서
/앞에 둬라. /와*사이에 있는 파라미터는 기본 규칙대로 position/keyword 둘 다 허용해라.
Item 38: 데코레이터는 functools.wraps로 정의해라
- 데코레이터는 런타임에 한 함수가 다른 함수를 수정하는 문법이다.
- 데코레이터를 잘못 쓰면 디버거 같은 introspection 도구에서 이상하게 보일 수 있다.
- 커스텀 데코레이터를 만들 때는 반드시
functools.wraps를 써서 메타데이터가 깨지지 않게 해라.
Item 39: glue 함수는 lambda보다 functools.partial을 선호해라
lambda는 인자 재배치나 특정 값 고정으로 인터페이스를 맞출 때 짧게 쓸 수 있다.functools.partial은 위치/키워드 인자를 고정해서 새 함수를 만드는 범용 도구다.- 인자 순서를 바꿔야 하는 경우에만
lambda를 쓰고, 그 외에는partial로 고정해라.
Item 40: map/filter 말고 comprehension을 써라
list comprehension은map/filter보다 보통 더 명확하다.lambda를 강요하지 않기 때문이다.list comprehension은if절로 입력 항목을 쉽게 건너뛸 수 있다.map은 단독으로 이걸 못 한다.dict와set도comprehension으로 만들 수 있다.list comprehension은 평가 시 결과를 전부 메모리에 만든다. 입력이 크면 메모리 많이 먹는다고 생각해라.
Item 41: comprehension에 control subexpression 2개 넘게 넣지 마라
comprehension은 여러 레벨 루프와 여러 조건을 지원한다.- 제어 subexpression이 2개를 넘어가면 읽기 너무 어렵다. 피하라.
Item 42: assignment expression으로 comprehension의 반복을 줄여라
assignment expression은comprehension/generator expression에서 한 번 계산한 값을 같은 식 안에서 재사용하게 해준다. 가독성과 성능을 같이 챙겨라.- 조건 밖에서
assignment expression을 억지로 쓰지 마라. 안정적으로 동작하지 않는 경우가 있다. comprehension에서assignment expression으로 만든 변수는 바깥 스코프로 새어 나간다. 반면comprehension의 루프 변수는 기본적으로 새지 않는다.
Item 43: 리스트 반환 대신 generator를 고려해라
- 누적 결과 리스트를 만들어 반환하는 것보다 generator가 더 명확한 경우가 많다.
- generator는 함수 바디의
yield로 전달한 값들을 순서대로 만들어내는 이터레이터를 반환한다. - generator는 모든 입력/출력을 메모리에 쌓지 않는다. 그래서 입력이 매우 커도 동작하게 만들어라.
Item 44: 큰 list comprehension이면 generator expression을 고려해라
- 입력이 큰데
list comprehension을 쓰면 메모리 때문에 문제가 날 수 있다. generator expression은 출력을 하나씩 만들기 때문에 메모리 문제를 피한다.generator expression은 다른generator expression의for입력으로 넘겨서 조합해라.- 체이닝해도 빠르고 메모리 효율이 좋다.
Item 45: 여러 generator는 yield from으로 합쳐라
yield from은 중첩된 여러 generator를 하나의 generator로 합치는 문법이다.yield from으로 중첩 generator를 수동으로 돌면서yield하는 boilerplate를 없애라.
Item 46: generator에 데이터를 넣으려면 send 말고 “입력 이터레이터”를 인자로 넘겨라
send는 generator에 값을 주입해서yield표현식이 값을 받게 만들 수 있다.send와yield from을 섞지 마라. 예상 못 한 타이밍에None이 튀어나오는 등 놀라운 동작이 생길 수 있다.- generator들을 조합해야 하면
send로 밀어 넣지 말고, 입력 이터레이터를 인자로 전달하는 구조로 짜라.send는 피하라.
Item 47: 상태 전이는 generator throw 말고 클래스로 관리해라
throw는 generator 안에서 “마지막yield지점”에 예외를 다시 던질 수 있다.throw를 쓰면 예외 raise/catch를 위해 중첩과 boilerplate가 늘어난다. 가독성이 깨진다.- 반복 처리 + 상태 전이가 필요하면 stateful 클래스를 만들어라. iteration과 state transition을 메서드로 분리해라.
7. Classes and Interfaces
Item 48: 단순 인터페이스면 클래스 말고 함수를 받아라
- 클래스 정의/인스턴스화 대신, 단순한 컴포넌트 인터페이스는 함수로 해결해라.
- 파이썬에서 함수/메서드 레퍼런스는 first-class다. 다른 타입처럼 표현식에 넣어라.
- 클래스 인스턴스를 함수처럼 호출 가능하게 하려면
__call__을 구현해라. - 상태가 필요한 “함수”가 필요하면 stateful closure로 억지로 만들지 마라.
__call__을 가진 클래스를 고려해라.
Item 49: isinstance 분기 함수 말고 OOP 다형성을 써라
isinstance로 타입을 검사해서 동작을 바꾸는 코드를 남발하지 마라.- 다형성(polymorphism)은 런타임에 “가장 구체적인 서브클래스 구현”으로 메서드 호출을 디스패치하는 OOP 기법이다.
- 많은 타입 분기가 필요하면
isinstance체인 대신 다형성으로 설계해라. 읽기/유지보수/확장/테스트가 쉬워진다.
Item 50: OOP 대신 함수형 스타일이 필요하면 functools.singledispatch를 고려해라
- OOP는 클래스 중심으로 코드가 흩어지기 쉽다. 큰 프로그램에서 관리가 어려워질 수 있다.
- single dispatch는 메서드 다형성 대신 “함수 기반” 동적 디스패치를 제공해서 관련 기능을 한곳에 모으기 좋다.
- 파이썬은
functools에singledispatch데코레이터를 제공한다. 필요하면 써라. - 서로 독립적인 시스템들이 같은 데이터 타입을 대상으로 동작한다면, OOP 대신 single dispatch의 함수형 스타일이 더 맞을 수 있다.
Item 51: 가벼운 클래스 정의엔 dataclasses를 선호해라
dataclasses의@dataclass로 boilerplate 없이 가볍고 실용적인 클래스를 정의해라.- 표준 OOP 문법의 장황함과 실수 포인트를 줄이는 데
dataclasses가 도움이 된다. dataclasses는asdict/astuple같은 변환 헬퍼와field같은 고급 속성 제어도 제공한다.- 나중에 커스터마이즈가 더 필요해지면
dataclasses없이도 OOP 패턴을 직접 구현할 수 있어야 한다. 그 길로 옮길 준비를 해라.
Item 52: @classmethod 다형성으로 객체를 범용적으로 생성해라
- 파이썬 클래스는 생성자가 사실상 하나다.
__init__만 있다고 생각해라. - 대안 생성자가 필요하면
@classmethod로 만들어라. @classmethod다형성으로 “여러 구체 하위 클래스”를 공통 방식으로 생성/연결할 수 있게 해라.
Item 53: 부모 클래스 초기화는 super로 해라
- 파이썬의 표준
MRO(메서드 해석 순서)가 부모 초기화 순서 문제랑 다이아몬드 상속 문제를 정리해준다. - 부모 초기화나 부모 메서드 호출은
super()(인자 0개)로 해라.
Item 54: 기능은 mix-in 클래스로 조합하는 걸 고려해라
mix-in으로 해결 가능하면, 인스턴스 속성이나__init__까지 얹는 다중 상속은 피 해라.- 클래스별 커스터마이징이 필요하면, 인스턴스 단위로 끼울 수 있는 “플러그형 동작”도 같이 고려해라.
mix-in은 필요에 따라 인스턴스 메서드도 넣고, 클래스 메서드도 넣어라.- 작은 동작을
mix-in으로 만들고, 여러 개를 조합해서 복잡한 기능을 구성해라.
Item 55: private 속성보다 public 속성을 선호해라
- 파이썬에서
private속성은 컴파일러가 엄격하게 강제하지 않는다. - 처음부터 “서브클래스가 내부 API/속성을 더 활용할 수 있게” 설계해라. 아예 막아버리는 방향으로 가지 마라.
- 접근을 강제로 막으려 하지 말고,
protected필드는 문서로 규칙을 잡아서 서브클래스가 따라오게 해라. - 서브클래스를 네가 통제 못 하는 상황에서 “이름 충돌”을 피해야 할 때만
private속성을 고려해라.
Leave a comment