1. 파이썬의 버전을 파악할 것
python --version
또는
python3 --version
- 파이썬 버전은 3이 강력히 권장된다.
2. PEP 8 스타일 가이드를 따를 것
- PEP은 파이썬 개선 제안이라는 파이썬 코드 작성 가이드다.
- PEP 8은 깔끔한 파이썬 코드를 작성하는 방법을 자세히 알려준다.
- 일관된 스타일을 사용하면 코드에 더 친숙하게 접근하고, 코드를 더 쉽게 읽을 수 있다.
1) 공백
- 탭 대신 스페이스로 들여쓰기를 할 것
- 문법적으로 중요한 들여쓰기에는 4칸 스페이스를 사용할 것
- 라인 길이는 79자 이하일 것
- 긴 식을 다음 줄에 이어서 쓸 경우에는 4칸 스페이스를 더 들여쓸 것
- 최상위 함수와 클래스 선언 사이를 구분 짓기 위해 2줄을 띄울 것
- 클래스 안에서 메소드 사이에는 1줄을 비워둘 것
- 딕셔너리에서 키와 클론(:) 사이에는 공백을 넣지 않고, 콜론 다음에 스페이스를 하나 넣을 것
- 변수 대입에서 = 전후에는 스페이스를 하나씩만 넣을 것
- 타입 표기를 덧붙이는 경우에는 변수 이름과 콜론 사이에 공백을 넣지 않고, 콜론과 타입 정보 사이에는 스페이스를 하나만 넣을 것
nums: List[int] = [1, 2, 3]
2) 명명 규약
- 함수, 변수, 속성은 소문자 스네이크식 표기법을 사용할 것 - 예) snake_case
- 보호되어야 하는 인스턴스 속성은 일반적인 소문자 스네이크식 표기법을 따르되, _(밑줄)로 시작할 것 - 예) _snake_case
- 한 클래스 내에서만 쓰여야 하는 비공개 인스턴스 속성은 일반적인 소문자 스네이크식 표기법을 따르되, __(밑줄 2개)로 시작할 것 - 예) __snake_case
- 클래스는 파스칼식 표기법을 사용할 것 - 예) PascalCase
- 모듈 수준의 상수는 대문자 스네이크식 표기법을 사용할 것 - 예) SNAKE_CASE
- 클래스의 인스턴스 메소드는 첫 번째 인자로 self를 받을 것
- 클래스 메소드는 첫 번째 인자로 cls를 받을 것
3) 식과 문
- 긍정적인 식을 부정하지 말고 부정을 내부에 넣을 것
if not a is b # (X)
if a is not b # (O)
- 반복 가능한 객체가 비어있는지 검사할 때는 길이를 0과 비교하지 말고 'if not 객체' 조건을 사용할 것
- 반복 가능한 객체가 비어있지 않은지 검사할 때는 길이가 0보다 큰지 비교하지 말고 'if 객체' 조건을 사용할 것
- if, for, while, except 복합문을 한 줄로 표현하지 않고, 명확성을 위해 각 부분을 여러 줄에 나눠 배치할 것
- 식을 한 줄 안에 다 쓸 수 없는 경우, 식을 괄호로 둘러싸고 줄바꿈과 들여쓰기를 활용할 것 (\는 권장하지 않음)
4) 임포트
- from-import문은 항상 파일의 맨 위에 위치시킬 것
- 외부에서 임포트할 때는 절대적인 이름을 사용할 것 - 예) from django.views.generic import ListView
- 다른 모듈에서 임포트해야 할 때는 명시적 상대 임포트를 이용할 것
from .models import Item # O
from models import Item # X
- import *는 과다 로딩 및 덮어 쓰기 문제가 발생할 수 있으니 지양할 것
- 임포트는 다음과 같은 순서로 섹션을 나누고, 각 섹션 안에서는 알파벳 순서로 배치할 것
- 표준 라이브러리 모듈
- 코어 장고 모듈
- 장고와 무관한 외부 모듈
- 커스텀 모듈
+ 추가 개념)
- Pylint는 파이썬 소스 코드에 대한 유명한 정적 분석기로, PEP 8 스타일 가이드를 자동으로 실행해 주고, 실수하기 쉬운 다양한 유형의 오류를 감지해준다. 여러 IDE와 에디터에서도 비슷한 기능을 제공하는 플러그인들이 있다.
- 함수나 변수 등의 이름은 함축적으로 짓지 않도록 하자.
3. bytes와 str를 잘 구분할 것
- bytes에는 8비트 값의 시퀀스가 들어 있고, str에는 유니코드 코드 포인트의 시퀀스가 들어있다.
- b-문자열은 bytes 형 문자열을 나타낼 때 사용된다.
print('hello'.encode()) # b'hello' 출력
print(b'hello') # b'hello' 출력
- 유니코드 데이터를 인코딩하거나 디코딩하는 부분을 인터페이스의 가장 먼 경계 지점에 위치시키자.
- 처리할 입력이 원하는 문자 시퀀스인지 확실히 하려면 다음과 같은 도우미 함수를 사용하자.
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode('utf-8')
else:
value = bytes_or_str
return value
def to_bytes(bytes_or_str):
if isinstance(bytes_or_str, str):
value = bytes_or_str.encode(bytes_or_str)
else:
value = bytes_or_str
return value
- bytes와 str 인스턴스를 연산자에 섞어서 사용할 수 없다. 이진 데이터 파일을 다룰 때도 이진 모드('rb'나 'wb')를 사용해야 한다.
- 파일을 다룰 때 시스템 디폴트 인코딩을 파악해두고, 필요에 따라 open 함수에 encoding 파라미터를 명시적으로 전달하자.
import locale
print(locale.getpreferredencoding()) # 시스템 디폴트 인코딩 반환
4. 문자열 formatting에는 f-문자열을 사용할 것
- Formatting(형식화)이란, 미리 정의된 문자열에 데이터 값을 끼워 넣어서 사람이 보기 좋은 문자열로 저장하는 것이다.
- 파이썬 3.6부터는 형식화 방식으로 인터폴레이션을 통한 f-문자열 방식이 도입되었다. 이 문법에서는 형식 문자열 앞에 f 문자를 붙여야 한다.
- f-문자열은 위치 지정자 안에 임의의 파이썬 식을 직접 포함시키는 방식이다. 그래서 다음과 같은 장점들이 나오게 된다.
- 파라미터의 순서에 얽매이지 않음
- 불필요한 중복을 제거할 수 있음
- 식이 짧음
- 가독성이 좋음
key = 'val'
value = 1.356
print(f'{key} = {value:.2f}') # val = 1.36
다음과 같이 연산자뿐만 아니라 함수도 사용할 수 있고
for i, (item, count) in enumerate(pantry)
print(f'#{i+1}: {item.title():<10s} = {round(count)}')
함수의 파라미터도 변수로 줄 수 있다.
def add(x, y):
return x + y
a=1
b=2
print(f'{a+b} = {add(a, b)}') # 3 = 3
그리고 다음과 같이 파이썬 식을 형식 지정자 옵션에 넣을 수도 있다.
places = 3
number = 3.14159265
print(f'{number:.{places}f}') # 3.142
- C 스타일의 형식화(%)나 str.format 방식은 가독성면에서 권장되지 않는다. 즉, f-문자열을 택하자.
5. 복잡한 식을 쓰는 대신 도우미 함수를 작성할 것
- 코드를 줄여쓰는 것보다 가독성을 좋게 하는 것이 더 가치 있다.
- 특히 같은 로직을 반복해 사용할 때는 반드시 도우미 함수를 사용하자.
- boolean 연산자를 식에 사용하는 것보다 if-else 식을 사용하는 편이 가독성이 좋다.
6. 인덱스를 사용하는 대신 대입을 사용해 데이터를 언패킹하라
- 언패킹 구문을 사용하면 한 문장 안에서 여러 값을 대입할 수 있다. 튜플, 리스트, 시퀀스, 이터러블(중첩 포함)등 다양한 패턴을 언패킹 구문에 사용할 수 있다.
item = ('apple', 'banana')
# first = item[0] # 비추천
# second = item[1] # 비추천
first, second = item
print(first, second) # apple banana
- 언패킹 구문을 활용하여 임시 변수 없이도 간단하게 두 변수를 스왑할 수 있다. 아래의 경우에는 내부적으로 이름 없는 임시 튜플이 사용된다.
a = 3
b = 4
a, b = b, a
print(a, b) # 4 3
- 반복문에서도 다음과 같이 언패킹 구문을 활용할 수 있다.
snacks = [('apple', 500), ('banana', 300), ('lemon', 400)]
for idx, (name, price) in enumerate(snacks, 1): # 1부터 시작
print(f'#{idx}: {name}은 {price}원입니다.')
- 함수 인자(*args), 키워드 인자(**kwargs), 다중 반환 값 등에 대한 언패킹 기능도 제공된다.
7. range보다는 enumerate를 사용할 것
- enumerate 내장 함수는 루프 인덱스와 이터레이터의 다음 값으로 이뤄진 쌍을 넘겨준다. next 내장 함수 또는 for문을 통해 다음 원소를 가져올 수 있다.
snacks = [('apple', 500), ('banana', 300), ('lemon', 400)]
it = enumerate(snacks)
print(next(it)) # (0, ('apple', 500))
print(next(it)) # (1, ('banana', 300))
for idx, (name, price) in enumerate(snacks):
print(idx, name, price) # 반복마다 0 apple 500, 1 banana 300, 2 lemon 400이 순서대로 출력
- enumerate의 두 번째 파라미터(start)로 어디부터 수를 세기 시작할지 지정할 수 있다. 디폴트는 0이다.
snacks = [('apple', 500), ('banana', 300), ('lemon', 400)]
for idx, (name, price) in enumerate(snacks, 1):
print(idx, name, price) # 반복마다 1 apple 500, 2 banana 300, 3 lemon 400이 순서대로 출력
8. 여러 이터레이터에 동시에 접근하려면 zip을 사용할 것
- zip(x) : 동일한 개수로 이루어진 자료형을 하나씩 묶어서 zip 객체로 반환
print(list(zip([1,2,3],['a','b','c'],[7,8,9]))) # [(1, 'a', 7), (2, 'b', 8), (3, 'c', 9)]
- 예를 들어, names, counts 라는 리스트가 있다고 하면 다음과 같이 언패킹이 가능하다.
for name, count in zip(names, counts):
...
- 입력 이터레이터들의 길이가 서로 다르다면, zip의 경우에는 가장 짧은 이터레이터 길이까지만 튜플을 내놓는다. 그런데 이런식으로 긴 이터레이터의 뒷부분을 무시하는 것은 바람직하지 않기 때문에 itertools 내장 모듈의 zip_longest을 사용하는 것이 권장된다. zip_longest는 존재하지 않는 값이 있다면 자신에게 전달된 fillvalue로 대신하며, fillvalue의 기본값은 None이다.
9. 반복문 바로 뒤에 else 블록을 사용하지 말 것
- 반복문 바로 뒤에 나오는 else 블록을 사용함으로써 얻을 수 있는 표현력보다는 미래에 이 코드를 이해하려는 사람들이 느끼게 될 부담이 더 크다.
※ 반복문 바로 뒤에 나오는 else 블록은 루프가 끝나자마자 실행된다는 특징이 있다. 루프 중간에 break을 만나면 else 블록이 실행되지 않는다.
10. 왈러스 연산자를 사용해 반복을 피할 것
- 왈러스 연산자는 파이썬 언어에서 고질적인 코드 중복 문제를 해결하고자 파이썬 3.8 버전에서 새로 도입된 구문으로, 일반 대입문은 =을 사용하는 반면, 왈러스 연산자는 :=을 사용한다.
- 왈러스 연산자를 사용하면 조건식처럼 일반 대입문이 쓰일 수 없는 위치에서도 변수에 값을 대입할 수 있다.
- 예를 들어, 특정 변수에 함수의 결과값을 저장하는 동시에 if 조건식에도 활용하기 위해 다음과 같은 코드를 작성했다고 하자.
def add(a, b):
return a + b
if (val=add(6, 7)) > 10:
print("high")
else:
print("low")
print(val)
다음과 같이 문법 에러가 발생한다.
이 때, 왈러스 연산자를 사용하면 특정 변수에 대한 대입과 검증을 동시에 수행할 수 있다.
def add(a, b):
return a + b
if (val:=add(6, 7)) > 10:
print("high")
else:
print("low")
print(val)
while 조건식에서도 왈러스 연산자를 이용하면 유용한 경우가 많으니 적극 활용하도록 하자.
● 참고 자료 : 파이썬 코딩의 기술 개정 2판 - 브렛 슬라킨
'Python' 카테고리의 다른 글
[Python] 모범 코딩 전략(2) - 리스트와 딕셔너리 (0) | 2023.02.20 |
---|---|
[Python] 파이썬 웹 표준 라이브러리 (0) | 2023.01.19 |
[Python 간단정리 5] 정규 표현식 (0) | 2023.01.08 |
[Python 간단정리 4] 예외 처리 / lambda / 내장·외장 함수 (0) | 2023.01.07 |
[Python 간단정리 3] 클래스 / 모듈 / 패키지 (0) | 2023.01.06 |
댓글