[Python] PEP 8 : Style Guide for Python Code
PEP는 Python Enhance Proposal의 약자로 파이썬 향상 제안으로 직역할 수 있다. 파이썬 코드 작성법에 대한 가이드라인으로 생각하면 될 것 같다.
파이썬 개발자들의 관습이 된 PEP를 따른다면 가독성이 뛰어나고 협업 체계에 유리한 코드를 작성할 수 있다.
파이썬 유저라면 특히 파이썬 코드를 파이썬스럽게 작성하도록 하는 코딩 컨벤션인 PEP 8은 최소 한 번 이상 읽어 보는 것을 강력히 추천한다.
따라서 본 포스팅에서는 PEP 8의 내용을 카테고리별로 요약하여 정리한다. 영어 원문을 쓰지 않고 한국어로, 코드 예시를 포함하였다.
PEP 8 : Style Guide for Python Code
PEP 20이 파이썬이 추구하는 철학에 대한 것이라면, PEP 8은 그것을 실현하기 위한 방법이다.
파이썬 코드 스타일 가이드라는 이름에 맞게 구체적인 코딩 방법이 담겨 있다.
즉, 어떻게 코딩을 해야 Pythonic Code (파이썬스러운 코드)가 되는지 알아보자.
A Foolish Consistency is the Hobgoblin of Little Minds
- 어리석은 일관성은 속 좁은 도깨비다.
- 코드는 쓰여질 때보다 읽혀질 때가 훨씬 많다.
- 그래서 파이썬 코드를 작성할 때 가독성과 일관성은 중요하며 스타일 가이드는 이를 향상시키기 위함이다.
- 그러나 스타일 가이드가 적용될 수 없는 경우가 있다. 특히 PEP를 준수하기 위해 이전 버전과의 호환성을 깨지 마라.
- 가이드라인을 무시해도 되는 몇 가지 좋은 이유
- 가이드라인을 적용하면 코드가 더 읽기 어려워지는 경우. 심지어 이 PEP를 따르는 코드가 익숙한 사람에게도
- 주변의 코드와 일관성을 유지해야하는 경우(아마 역사적인 이유)
- 가이드라인이 도입되기 이전에 작성된 코드
- 스타일 가이드에서 권장하는 기능을 지원하지 않는 이전 버전의 파이썬과의 호환성을 유지해야할 경우
Code Lay-out | 코드 레이아웃(배치)
- 들여쓰기 수준당 4개의 공백(space)을 사용하라
- (), {}, [] 안에서 연속된 줄들은 파이썬의 암시적인 줄 연결이나 행잉 들여쓰기를 통해 수직으로 정렬해야한다.
- 행잉 들여쓰기를 사용할 때는 첫 번째 줄에 인자를 쓰지 않아야하고, 추가적 들여쓰기를 통해 연속된 줄이라는 것을 분명히 해야한다.
# Wrong # 수직 정렬을 하지않고 첫 줄에 인자들을 쓰면 가독성이 좋지 않다 foo = function_name(var_one, var_two, var_three, var_four) # print문과 구분되도록 더 들여쓰기 필요 def function_name( var_one, var_two, var_three, var_four): print(var_one)
# Correct # 첫 줄에 인자를 썼지만 수직정렬이 잘 됐다 foo = function_name(var_one, var_two, var_three, var_four) # 첫 줄에 인자 없이 hanging 들여쓰기 foo = function_name( var_one, var_two, var_three, var_four) # 아래 print문과 구별되도록 추가적 들여쓰기를 했다. def function_name( var_one, var_two, var_three, var_four): print(var_one)
연속된 줄에는 공백 4개 규칙이 선택사항이다.
- 탭(Tab) 을 쓸까 공백(Space) 을 쓸까
- 공백이 들여쓰기 방법으로 선호된다
- 탭은 이미 탭으로 들여쓰기된 코드와의 일관성을 위해 사용되어야 한다
- Python 3은 들여쓰기를 위한 탭과 공백의 혼합을 허용하지 않는다
- 최대 줄 길이
- 모든 줄은 최대 79자로 제한한다
- docstring 또는 주석과 같이 구조적 제한이 적은 긴 텍스트 블록은 72자로 제한한다
- 줄 바꿈은 이진 연산자의 앞? 뒤?
- 연산자의 뒤에서 줄바꿈하면 피연산자와 연산자가 멀리 떨어지게 된다
- 연산자의 앞에서 줄바꿈하면 더 읽기 좋은 코드가 된다
# Wrong # 연산자와 피연산자가 멀리 떨어져있다 income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest) # Correct: # 연산자와 피연산자를 매치시키기 쉽다 income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest)
- 빈 줄 사용
- 최상위 함수와 클래스 정의는 두 개의 빈 줄로 둘러싼다
- 클래스 내부의 메소드 정의는 하나의 빈 줄로 둘러싼다
- 추가 빈 줄은 관련된 함수들의 그룹을 분리하기 위해 아껴서 사용할 수 있다
- import
- import 문은 보통 분리된 줄에 있어야 한다
# Wrong import pandas, numpy # Correct import pandas import numpy
아래와 같이 사용하는 것은 괜찮다
from numpy import square, sign
- 와일드카드 임포트(from module import *)는 피해야한다. 혼란을 야기한다.
String Quotes | 문자열 따옴표
파이썬에서 따옴표로 둘러싼 문자열과 쌍따옴표로 둘러싼 문자열은 동일하다.
규칙을 선택하고 고수하라. 그러나 문자열에 따옴표나 큰따옴표가 포함된 경우 나머지 하나를 사용하여 문자열에 백슬래시()를 사용하지 않도록함으로써 가독성을 향상시켜야한다.
삼중 따옴표를 둘러싼 문자열에 대해서는, PEP 257의 docstring 규칙과 일치되도록 항상 쌍따옴표를 사용해야한다.
Whitespace in Expressions and Statements | 표현식과 명령문에서의 공백
-
공백을 추가하는 것을 피해야하는 상황
1) (), {}, [] 바로 안쪽
# Wrong [ 1, 2, lst[ 3 ] ] # Correct [1, 2, lst[3]]
2) 쉼표와 그 뒤에 오는 닫는 괄호 사이
# Wrong t = (1, ) # Correct t = (1,)
3) 쉼표, 세미콜론, 콜론 바로 앞
# Wrong if x == 3 : return x , y # Correct if x == 3: return x, y
4) 함수 호출시 인자 목록을 시작하는 여는 괄호 바로 앞
# Wrong func (100) # Correct func(100)
5) 인덱싱이나 슬라이싱을 시작하는 여는 괄호 바로 앞
# Wrong dct ['key'] = lst [index] # Correct dct['key'] = lst[index]
6) 연산자끼리 정렬하기 위해 여러 개의 공백 사용
# Wrong x = 1 y = 2 long_variable = 3 # Correct x = 1 y = 2 long_variable = 3
- 다음 연산자들은 항상 단일 공백으로 둘러싸야한다
- 대입이나 복합대입연산자 (=, +=, -= 등)
- 비교 연산자 (==, <, <=, >, >=, is, in 등)
- 논리 연산자 (and, or, not)
-
우선 순위가 다른 연산자들을 사용하는 경우 우선 순위가 낮은 연산자 주위에 공백을 사용해야한다.
-
연산자의 양쪽에 같은 개수의 공백을 사용해야한다.
# Wrong i=i+1 total +=1 x = x * 2 - 1 result = x * x + y * y c = (a + b) * (a - b) # Correct i = i + 1 total += 1 x = x*2 - 1 result = x*x + y*y c = (a+b) * (a-b)
-
키워드 인자 혹은 디폴트 파라미터 값을 나타낼 때는 = 앞뒤로 공백을 사용하지 않아야한다.
# Wrong def complex(real, imag = 0.0): return magic(r = real, i = imag) # Correct def complex(real, imag=0.0): return magic(r=real, i=imag)
When to Use Trailing Commas | 후행 쉼표를 사용하는 경우
요소가 한 개인 튜플을 만들 때 필수인 경우를 제외하면, 후행 수미표는 보통 선택사항이다.
버전 관리 시스템 등에서 항목들의 목록이 나중에 확장될지도 모를 때 도움이 된다.
# Wrong
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)
# Correct
FILES = [
'setup.cfg',
'tox.ini',
]
initialize(FILES,
error=True,
)
각 항목을 하나의 줄에 넣어주며 관리하고, 더이상 없을 경우에는 다음 줄에서 괄호를 닫는다.
Comments | 주석
- 코드와 맞지 않는 주석은 없는 게 낫다. 항상 최신 상태로 유지해야한다.
- 인라인 코멘트(코드와 같은 줄에 있는 코멘트)는 드물게 사용해야한다.
- 사용한다면 2개 이상의 공백으로 코드와 분리되며 #과 하나의 공백으로 시작해야한다.
-
명확한 코드에 대한 인라인 주석은 산만하게 만든다.
# Wrong x = x + 1 # Increment x # Useful # 어떤 목적인지에 대한 주석 x = x + 1 # Compensate for border
Naming Conventions | 이름짓기 관습
- 일반적인 네이밍 스타일
- b (single lowercase letter) : 단일 소문자
- B (single uppercase letter) : 단일 대문자
- lowercase : 소문자
- lower_case_with_underscores : 밑줄을 포함하는 소문자 (snake case)
- UPPERCASE : 대문자
- UPPER_CASE_WITH_UNDERSCORES : 밑줄을 포함하는 대문자
- CapitalizedWords : 각 단어의 첫 글자는 대문자 (CapWords)
- camelCase : 첫 글자는 소문자, 그 뒤 각 단어 첫 글자는 대문자
- Capitalized_Words_With_Underscores : 이렇게는 쓰지 말자 (ugly)
-
‘l’ (소문자 엘), ‘O’ (대문자 오), ‘I’ (대문자 아이)는 단일 문자 변수 이름으로 절대 쓰지 않아야한다.
- 클래스 이름은 CapWord 표기법을 사용한다
- 함수, 메소드, 변수 이름은 snake case를 사용한다
- 상수는 보통 모듈 수준에서 정의되며 밑줄을 포함하는 대문자를 사용한다
Programming Recommendations | 프로그래밍 권장사항
-
None과 같은 singletons에 대한 비교는 ==를 사용하지 않고 is, is not으로 한다.
class Foo(): def __eq__(self, obj): return obj is None foo = Foo() print(foo == None) # True print(foo is None) # False
-
not … is 보다 is not 연산자를 사용해야한다.
# Wrong if not foo is None: # Correct if foo is not None:
-
식별자에 직접 람다 표현을 대입하는 대신 항상 def 구문을 사용해야한다.
# Wrong f = lambda x: x * 2 # Correct def f(x): return x * 2
- 예외처리를 할 때 가능하다면 특정 예외를 언급해야한다.
- try / except 구문의 try 는 필요한 최소의 코드로 제한해야 한다.
-
함수 안에서 return 문은 반환할 값이 없는 경우 명시적으로 return None을 사용해야한다.
# Wrong def foo(x): if x >= 0: return math.sqrt(x) def bar(x): if x < 0: return return math.sqrt(x) # Correct def foo(x): if x >= 0: return math.sqrt(x) else: return None def bar(x): if x < 0: return None return math.sqrt(x)
-
접두사와 접미사를 확인하기 위해 문자열 슬라이싱보단 .startswith() 와 .endswith()를 사용해야한다.
# Wrong if foo[:3] == 'abc': # Correct if foo.startswith('abc'):
직관적이고 에러가 적다
-
불리언 값의 비교는 == 연산자를 이용해 True나 False와 비교하지 않아야한다.
# No if greeting == True: # No if greeting is True: # Yes if greeting:
PEP 20과 PEP 8을 정독하면 파이썬을 더 이해할 수 있다.
파이썬이 추구하는 것의 키워드는 직관성, 가독성, 일관성으로 보인다.
PEP 8 원문 : https://peps.python.org/pep-0008/
댓글남기기