PEP8 -- Style Guide for Python Code
PEP 8 -- Style Guide for Python Code 정리본
www.python.org/dev/peps/pep-0008/
PEP 8 -- Style Guide for Python Code
The official home of the Python Programming Language
www.python.org
0. Introduction
PEP 8 (Python Enhancement Proposal) 8 은 파이썬 코드의 작성 규칙 (coding convnetions)에 대해 설명하는 문서임.
Guido (파이썬 개발자) 의 중요한 인사이트 중 하나는 코드는 작성하는 것보다 읽는 것이 더 쉬워야 한다는 원칙.
따라서 PEP 8은 다음 2가지를 목표로 한다.
- 파이썬 코드의 가독성 향상
- 파이썬 코드의 작성법을 일관성 있게 (consistency) 하는 것.
다만, PEP 8 따라 코드를 작성함으로부터 일관성이 지켜지지 않는다면, 일관성이 지켜지는 코드 작성법이 우선한다.
다음과 같은 상황은 가이드라인을 준수하지 않아도 되는 대표적인 사례이다.
- PEP에 따라 코드를 읽는 사람임에도 불구하고, PEP 8을 적용하는 것이 코드를 더 읽기 어렵게 만드는 경우
- 기존에 PEP를 준수하지 않고 작성된 코드와의 일관성을 유지하는 경우
- 코드가 PEP 작성 시기보다 앞서며, 코드를 수정할 필요가 없는 경우
- 예전 버전의 파이썬으로 작성된 코드가 PEP를 따를 때, 작성된 코드가 작동하지 않을 경우
1. Code Lay-out
1) Indentation
Indentation (들여쓰기)는 한번에 4개 공백 (space)를 사용한다.
연속된 줄들은 (), {}, [] 안에서
(1) 파이썬의 암묵적인 줄 연결 방식 (vertically using Python's implicit line),
(2) 또는 hanging indent를 사용하여 줄바꿈됨 요소들을 정렬해야 함.
hanging indent를 사용할 때 다음 사항이 고려되어야 함.
Correct :
# Correct:
# Aligned with opening delimiter.
# 여는 구분 기호로 정렬
foo = long_function_name(var_one, var_two,
var_three, var_four)
# Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
# 아랫줄과 구분을 위해 더 많은 들여쓰기를 포함한 경우
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# Hanging indents should add a level.
foo = long_function_name(
var_one, var_two,
var_three, var_four)
* Hanging indentation is a type-setting style where all the lines in a paragraph are indented except the first line.
* Hanging indentation은 first line을 제외한 모든 구문이 모두 indented 된 type-setting style을 의미함.
Wrong :
# Wrong:
# Arguments on first line forbidden when not using vertical alignment.
# 수직 정렬이 되어있지 않다면, first line에 인자를 작성하면 안 됨!
foo = long_function_name(var_one, var_two,
var_three, var_four)
# Further indentation required as indentation is not distinguishable.
# 이후 구문 (e.g. print(var_one))과 구별이 되도록 추가의 들여쓰기가 필요함!
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
Optional :
- hanging indents가 꼭 4개의 공백일 필요는 없음 (e.g. 2개의 공백)
# Hanging indents *may* be indented to other than 4 spaces.
# hanging indents는 꼭 4개의 공백일 필요는 없음!
# 여기서는 2개의 공백!
foo = long_function_name(
var_one, var_two,
var_three, var_four)
- if 조건문의 조건이 여러 줄에 걸쳐 써야 할 정도로 길 때,
- if (2글자) + 공백 (1글자) + ( (1글자) => 총 4글자로 구성되어, 기존의 4개의 공백과 구분되지 않을 경우가 발생한다. PEP는 이러한 경우 명확한 지침은 없으며, Optional 한 성격을 가진다.
# No extra indentation.
# 추가 들여쓰기가 없다!
if (this_is_one_thing and
that_is_another_thing):
do_something()
# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
# 문법 강조를 지원하는 에디터에서는 어느 정도 구별이 되도록 코멘트를 넣는다.
if (this_is_one_thing and
that_is_another_thing):
# Since both conditions are true, we can frobnicate.
do_something()
# Add some extra indentation on the conditional continuation line.
# 조건문의 연속된 줄에 추가 들여쓰기를 한다!
if (this_is_one_thing
and that_is_another_thing):
do_something()
list 등의 (), {}, [] 닫는 괄호의 경우, 마지막 줄의 첫번째 요소 바로 아래 맞추어도 된다.
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
혹은 공백 없이 라인의 가장 앞에 맞추어도 된다.
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
2) Tabs or Spaces?
Space (공백)이 들여쓰기 방법으로 가장 선호된다.
Tabs은 이미 tab으로 들여쓰기가 된 코드와 일관성을 유지해야 할 경우에만 사용되어야 한다.
Python3
들여쓰기 방식으로 space와 tab의 혼용을 허용하지 않는다.
Python2
Tab과 space가 혼합된 들여쓰기가 있으면, space로만 변환해야 함.
python2 코드를 Commandar (or Terminal) 환경의 인터프리터에 -t 옵션과 함께 실행하면 탭과 스페이스를 잘못 혼합한 코드에 대해 경고를 줌. 만약 -tt 옵션을 사용하면 이 경고가 오류가 됨. (해당 옵션들은 파이썬 PEP8에서 적극 권장하는 부분)
즉, tab과 space는 절대 섞어 쓰면 안됨.
만약 탭을 사용하더라도, 탭이 space 4칸으로 변환되어야 함.
3) Maximum Line Length
한 행에는 최대 79글자까지만 넣도록 함.
- 아직까지 한 행에 80글자까지만 표시할 수 있는 장비들이 많이 남아있고, 창 하나에 80글자만 표시하도록 강제할 경우 여러 창을 열어서 늘어놓고 작업할 수 있음.
- 80글자 제한이 있는 장치에서 자동 줄 바꿈 (wrapping)이 일어날 경우, 코드의 시각적인 구조가 망가지기 때문에 코드 한 행을 최대 79글자로 제한함.
텍스트가 길게 늘어지는 경우 (e.g. docstring 혹은 주석문) 에는 72글자로 제한하는 것을 권장함.
글자가 많은 행에 줄바꿈을 적용할 경우:
- 괄호, 중괄호, 대괄호 등의 내부에 여러 행의 코드를 적음. 파이썬에서 해당 코드는 암묵적으로 계속 이어지는 것으로 처리됨.
- 어떠한 경우에는 백슬래시 (backslash)를 사용해 연속되는 문장의 줄바뀜을 표현하는 것이 적절함. (아래 예시)
- with 구문은 implicit continuation이 사용될 수 없고, 이러한 경우 백슬래시 사용이 적절함.
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
4) Should a Line Break Before or After a Binary Operator?
이항 연산자의 줄바꿈 위치
- 연산자의 앞, 뒤 모두 허용함
- 다만, 이항 연산자의 앞에서 줄바꿈 하는 것을 추천함.
# YES: 연산자 이전에 줄바꿈하여 연산자와 이어지는 코드가 보기 좋음
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
# NO: 연산자 이후에 줄바굼하여 이어지는 코드를 보기 어려움
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
5) Blank Lines
빈 줄은 클래스 또는 함수간의 정의를 구분할 때 사용하고, 코드 내에 연관성이 있는 코드 덩어리를 묶는데 사용함.
- top-level function, top-level class 들의 정의를 구분할 때는 두 줄 띄어 구분
- 클래스 내에 정의한 메소드들은 한 줄 띄어 구분
- 함수 내에 연관성 있는 코드 덩어리를 구분할 때 빈 줄을 사용할 수 있음
a bunch of related one-liners (한 줄까지 코드가 뭉쳐있을 때, e.g. 임시 코드, 일련의 미구현 코드) 의 경우 빈 줄을 생략할 수 있음.
파이썬은 control-L (^L) 문자를 공백으로 취급함. 많은 프로그램이 이 문자를 page separator로 취급하며, 파일 내에서 서로 연관성이 있는 단락을 페이지별로 구분하는데 사용할 수 있음. 특정 편집기나 웹 기반의 코드 뷰어는 control-L (^L)을 form feed 문자로 인식하지 않을 수 있으며, 이 경우 form feed를 대신하는 다른 문자가 control-L (^L) 문자의 위치에 표시됨.
6) Source File Encoding
파이썬 배포용 코드는 항상 UTF-8 (python2 의 경우 ASCII) 를 사용해야 함.
python3의 기본 인코딩은 UTF-8 이며, UTF-8을 사용한다면 인코딩을 따로 명시할 필요 없음 (python2 의 경우 ASCII)
7) Imports
import는 보통 행으로 구분되어야 함.
# Correct:
import os
import sys
# Wrong:
import sys, os
하지만 다음과 같이 사용하는 것은 괜찮음.
- from으로 동일한 곳에서 여러 모듈을 import 하는 경우
# Correct:
from subprocess import Popen, PIPE
import는 항상 파일의 맨 위에 작성함.
- 파일 상단의 파일 주석과 Docstrings 바로 아래 - 전역변수 위
다음 그룹들을 분류하여 빈 줄 하나를 넣어 구분되도록 정의하는 것을 권장함.
- Standard library imports (표준 라이브러리)
- Related third party imports
- Local application/library specific imports
절대경로를 이용하여 import 하는 것이 권장됨.
- 상대경로보다 더 readable 하며, 잘 작동하기 때문
- 상대경로를 이용하여 import 하는 것은 피하는 것이 좋지만, 복잡한 패키지 레이아웃이 있는 곳에서 사용되며, 절대경로 import가 불필요하다고 생각되면 상대경로를 사용할 수 있음.
#절대경로
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
#상대경로
from . import sibling
from .sibling import example
implicit(암묵적인 상대경로) relative import는 절대 사용되어서는 안되며, python3에서는 삭제됨.
모듈 안에 있는 클래스를 import 할 때는 다음과 같이 사용할 수 있음.
from myclass import MyClass
from foo.bar.yourclass import YourClass
만약 동일 이름의 local 이름과 충돌하는 경우, 다음과 같이 모듈을 먼저 import 함.
- 코드에서는 'myclass.MyClass', 'foo.bar.yourclass.YourClass'로 사용.
import myclass #모듈을 먼저 import 하고, myclass.MyClass로 사용
import foo.bar.yourclass #local class import 하고, foo.bar.yourclass.YourClass 로 사용.
Wildcard import (<from <module> import *)는 명확하지 않고, 코드를 읽는 사람과 자동화된 툴에게 혼동을 일으키므로 사용하지 않음.
- Wildcard import에 대해 사용이 용인되는 경우는 public API의 일부로서 internal interface 가 다시 개시된 경우임.
- e.g. optional한 accelerator module로부터 python implementation 이 overwriting 되고, 정확히 어떤 definitions이 overwritten 되었는지 확인되지 않을 때. 에는 Wildcard import가 허용됨.
- e.g. overwriting a pure Python implementation of an interface with the definitinons from an optional accelerator module and exactly which definitions will be overwritten isn't known in advance.
8) Module Level Dunder Names
Module level 'dunders' (즉. __가 이름 앞뒤로 쓰이는) (e.g. __all__, __author__, __version__, 등) 은 module docstring 뒤, import 문 전에 쓰여져야 함.
예외) from __future__ import 는 반드시 docstring 뒤에 가장 먼저 작성되어야 함.
"""This is the example module.
This module does stuff.
"""
from __future__ import barry_as_FLUFL
__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
import os
import sys
2. String Quotes
파이썬에서는 ''와 ""로 생성된 문자열을 따로 구분하지 않고, 동일하게 취급됨. PEP에서도 따로 권유하지 않음.
하지만, 따옴표 내부에 따옴표를 사용해야 하는 경우 서로 다른 따옴표를 사용.
- 가독성을 해치는 백슬러시 사용을 피할 수 있음.
docstring에 사용되는 따옴표 3개는 꼭 두개까지 따옴표 ("")를 사용.
- docstring의 일관성을 유지하기 위함.
3. Whitespace in Expressions and Statements
1) Pet Peeves
다음과 같은 상황에서는 여분의 공백 문자를 사용하지 않음.
괄호, 중괄호, 대괄호 내부에 연결되는 부분
# Correct:
spam(ham[1], {eggs: 2})
# Wrong:
spam( ham[ 1 ], { eggs: 2 } )
콤마와 닫는 괄호 사이
# Correct:
foo = (0,)
# Wrong:
bar = (0, )
콤마, 세미콜론, 콜론의 이전 위치
# Correct:
if x == 4: print x, y; x, y = y, x
# Wrong:
if x == 4 : print x , y ; x , y = y , x
슬라이스에서의 공백
- 슬라이스에서 콜론은 이진연산자와 같이 적용되며, 양쪽에서 같은 크기를 가짐.
- 확장된 슬라이스에서는 두 개의 콜론은 같은 간격을 가져야 함.
- 예외) 슬라이스 파라미터가 생략되면, 공백도 생략됨.
# Correct:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step] #예외) 슬라이스 파라미터가 생략되어, 공간도 생략됨.
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
# Wrong:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]
여는 괄호 직전에 띄우지 않음.
# Correct:
spam(1)
# Wrong:
spam (1)
dict의 경우, 여는 괄호 직전에 띄우지 않음.
# Correct:
dct['key'] = lst[index]
# Wrong:
dct ['key'] = lst [index]
변수 선언 및 할당 시, 한칸씩만 띄어주면 됨. 줄을 맞추기 위해 과도하게 띄어쓰기를 하지 않음.
# Correct:
x = 1
y = 2
long_variable = 3
# Wrong:
x = 1
y = 2
long_variable = 3
2) Other Recommendations
문장의 마지막에 공백 사용 하지 않을 것
- 해당 공백으로 인해서 backslash 등이 제대로 작동되지 않을 수 있는데, 공백이 눈에 잘 띄지 않아 혼란을 야기할 수 있음.
할당 (=), 증감 연산자 (+=, -=), 비교 연산자 (==, <, >, !=, <>, >=, <=, in, not in, is, is not), Boolean 연산자 (and, or, not)을 사용할 때 앞 뒤로 공백
- <> : not equal to. != 와 같은 의미, python3에서는 삭제됨.
우선순위가 다른 연산자들을 함께 쓸 때, 우선순위가 가장 낮은 연산자 주위로 공백을 넣어 구분.
# Correct:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
# Wrong:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
function annotations(:, -> 등)을 사용한다면, 양 옆에 공백을 넣어줘야 함.
- function annotation: bluese05.tistory.com/78
# Correct:
def munge(input: AnyStr): ...
def munge() -> PosInt: ...
# Wrong:
def munge(input:AnyStr): ...
def munge()->PosInt: ...
키워드 독립변수 (keyword argument) 혹은 기본 파라미터 값 (default value)을 나타내기 위해 '=' 주변에 공백은 사용하지 않음.
# Correct:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
# Wrong:
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
그러나, 함수의 기본값(default value)과 argument annotation을 합칠 때, '=' 주변에 공백을 사용함.
# Correct:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
# Wrong:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...
합성 구문 (Compound statements, multiple statements on the same line) 은 권장되지 않음.
# Correct:
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
# Wrong:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
if/for/while 구문에서 같은 줄에 짧은 바디가 같이 놓이는 것은 괜찮지만, 여러 줄을 이런식으로 구성하는 것은 하지 않을 것을 권고함.
# Wrong (Rather not):
if foo == 'blah': do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
# Wrong (Definitely not):
if foo == 'blah': do_blah_thing()
else: do_non_blah_thing()
try: something()
finally: cleanup()
do_one(); do_two(); do_three(long, argument,
list, like, this)
if foo == 'blah': one(); two(); three()
4. When to Use Trailing Commas
Trailing Commas는 선택적으로 사용할 수 있지만, 1개의 요소만 있는 튜플을 만들 때는 반드시 trailing commas를 넣어줘야 함.
- 튜플임을 헷갈리지 않도록 괄호를 넣어주는 것이 권장됨.
# Correct:
FILES = ('setup.cfg',)
# Wrong (Ok, but confusing):
FILES = 'setup.cfg',
Trailing Commas를 중복해서 사용하는 경우
- list of values, arguments or imported item이 추가될 것임을 예상할 수 있음.
- 이러한 패턴은 한줄에 하나의 요소를 적고, 닫는 괄호를 다음 line에 추가함.
- 동일 라인에 모든 요소를 정의하는 것은, 좀 이상한 것 같음.
# Correct:
FILES = [
'setup.cfg',
'tox.ini',
]
initialize(FILES,
error=True,
)
# Wrong:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)
5. Commets
코드와 반대되는 주석은 주석이 없는 것보다 못함. 코드가 업데이트 될 때, 주석을 함께 업데이트 하는 것을 당부함.
주석은 완전한 문장이어야 하며, 첫번째 글자가 소문자 식별자로 시작되지 않는 한, 대문자로 적음.
마지막 문장을 제외하고는 문장의 끝에 두 개의 스페이스(공백)를 사용하도록 함.
영어 사용.
1) Block Comments
블럭 주석은 일반적으로 완전한 문장의 조합으로, 하나 이상의 단락으로 구성되어 있음.
블럭 주석은 일반적으로 거의 모든 코드에 적용되며, 코드로서 같은 레벨로 들여쓰기 됨.
각각의 블록 주석은 #와 하나의 스페이스로 시작함.
2) Inline Comments
인라인 주석은 구문과 같은 라인에 있는 주석임.
인라인 주석은 구문으로부터 최소 2개의 스페이스로 구분되며, #과 하나의 스페이스로 시작함.
인라인 주석은 명확하지 않으면, 혼란을 야기하기 때문에 적당히 사용할 것을 권고함.
#Wrong
x = x + 1 # Increment x
#Correct
x = x + 1 # Compensate for border
3) Documentation Strings
좋은 documentation string (a.k.a 'docstrings') 위해서 PEP 257을 참고.
- PEP 267: www.python.org/dev/peps/pep-0257/
모든 public modeuls, functions, classes, and methods에 대해 docstrings을 작성함.
- Non-public 메서드에 대해서는 docstrings이 필요하지는 않지만, 메서드가 어떤 역할인지 설명하는 주석을 달아야 하고, 이 주석은 def 라인 다음에 위치해야 함.
중요) docstrings을 끝내는 """ 는 마지막 줄에 혼자서 작성되야 함.
- 만약 한줄로 docstrings이 작성된다면, 닫는 """ 을 같은 줄에 작성함.
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
"""Return an ex-parrot."""
6. Naming Conventions
- 파이썬 라이브러리의 네이밍 작성 규칙은 다소 엉망이기 때문에, 완벽한 일관성을 찾기는 힘듦
- 그럼에도 불구하고, 권장되는 naming standard를 제시함.
- 새로운 모듈과 패키지에서는 해당 기준에 맞춰 작성되어야 함.
- 그러나, 현재 다른 스타일을 가지고 있는 라이브러리가 존재하는 곳에서는 내부적으로 일관성이 있게 하는 것이 선호됨.
1) Overriding Principle
API의 Public 파트로써, 유저에게 보여지는 이름:
- 실행(implementation)이 아닌,
- 사용법(usage) 을 반영하는 작성규칙을 따라야 함.
2) Descriptive: Naming Styles
서로 다른 naming style이 존재하며, 아래의 naming style은 일반적으로 널리 사용되는 style
- b (single lowercase letter)
- B (single uppercase letter)
- lowercase
- lower_case_with_underscores
- UPPTERCASE
- UPTTER_CASE_WITH_UNDERSCORES
- CapitializedWords (CamelCase, CapWords, StudlyCaps로 알려짐)
- CapWords에서 줄임말을 사용할 때, 줄임말의 글자는 모두 대문자로 사용함.
- e.g. HttpServerError 보다는 HTTPServerError
- CapWords에서 줄임말을 사용할 때, 줄임말의 글자는 모두 대문자로 사용함.
- mixedCase
- 첫 글자가 소문자이기 때문에 CapitializedWords와는 다름)
- Capitailized_Words_With_Underscore
- ugly!
leading underscores (앞에 있는 _)와 trailing underscores (뒤에 있는 _) 를 파이썬에서 사용할 때 다음과 같이 사용함.
코딩을 하면서 이름을 지을 때는 single leading underscore 와 single trailing underscore만 사용하는 것이 좋음.
- _single_leading_underscore: 내부적으로 사용하는 변수를 의미
- single_trailing_underscore: 파이썬에서 기본 키워드와 겹치는 것을 피하기 위함
- __double_leading_underscore: 더블 언더스코더 (__)는 name mangling과 관련된 것. 만약 __method라고 이름을 지으면 name mangling에 의해 _ClassName__method로 변경됨. 이름이 변경되기 때문에 ClassName.__method로 접근할 수 없음. 따라서 일반적인 경우로는 사용하지 않는 것이 좋음.
- __double_leading_and_trailing_underscore__: Magic 객체. 파이썬에서 특수 용도로 예약되어 있음. (__init__, __import__, __file__), 따라서 이름을 정의해서 사용하면 안되고, 문서화되어 있는 항목들만 사용해야 함.
3) Prescriptive: Naming Convnetions
(1) Names to Avoid
l (소문자 L), O (대문자 o), I (대문자 i) 는 한 글자 변수이름으로써 사용하지 않음.
- 몇몇의 폰트에서, 해당 단어들을 숫자 1과 숫자 0과 구분이 쉽지 않으므로, i 대신에 I (대문자 i) 를 사용함.
(2) ASCII Compatibility
standard library 내에서 사용되는 변수의 이름은 ASCII와 호환 가능한 문자여야 함.
(3) Package and Module Names
모듈
- 모듈은 짧고, 모두 소문자인 이름을 가져야 함.
- 언더스코어는 가독성을 향상시킬 수 있으므로, 모듈의 이름에 사용될 수 있음.
패키지
- 패키지의 이름은 짧고, 모두 소문자인 이름을 가져야 함.
- 그러나 언더스코어는 사용할 수 없음. (모듈과 차이점)
C, C++로 쓰여진 확장 모듈 인터페이스를 제공하는 파이썬 모듈을 가질 때, C/C++ 모듈은 이름 앞에 언더스코어가 있어야 함.
(4) Class Names
클래스의 이름은 CapWords (CamelCase) 작성 규칙을 사용함.
built-in names에 대한 별도의 작성규칙
- 대부분의 built-in names은 하나의 단어 (혹은 두 단어가 함께 실행됨) (single words or two words run together)
- 보통 예외 이름(Exception Names: (6))과 내장 상수(builtin constants)에 사용되는 CapWords 작성 규칙이 사용됨.
(5) Type Variable Names
PEP 484에 소개된 타입 변수의 이름은 CapWord 방식을 사용함.
covariant (공변하거나) 혹은 contravariant (반변하는) 행위를 표시하기 위해 사용되는 변수들에 대해서는 접미사 _co, _contra 가 붙여지는 것을 권장함.
from typing import TypeVar
VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)
(6) Exception Names
예외는 클래스이기 때문에, 클래스 이름 작성 규칙이 적용됨.
다만, Error 접미사를 예외 이름에 사용함.
(7) Global Variable Names
이 변수들은 하나의 모듈 안에서만 사용하기를 권장함.
작성 규칙은 함수에 대한 작성 규칙 (Funcion and Variable Names (8)) 과 거의 비슷함.
__all__ 매커니즘
- from M import * 를 사용되게 설계된 모듈은 전역변수들을 exporting 을 막기위해 __all__ 매커니즘을 사용하여야 함.
- 혹은 언더스코어를 전역변수 앞에 접두사로 붙이는 구식의 작성규칙을 사용하여야 함. (모듈 내부적으로만 사용하는 변수 (module non-public) 이라는 의미)
(8) Function and Variable Names
함수 이름은 snake_case 로 작성
- 소문자
- 단어 사이를 언더스코어로 구분
예외) mixedCase를 사용하는 코드와 하위 호환성을 유지하기 위해, mixedCase 를 사용할 수 있음.
(9) Function and Method Arguments (메서드의 독립 변수)
instance 메소드의 첫 번째 인자의 이름은 'self' 를 사용함.
class 메소드의 첫 번째 인자의 이름은 'cls' 를 사용함.
만약 다른 코드와 이름이 동일하여, 충돌이 발생하는 경우
- 이름 뒤에 언더스코어를 넣어 충돌을 피할 수 있음.
- 이름을 모호하게 변경하는 것보다 언더스코어를 뒤에 붙여주는 것이 좋을 때가 많음.
(10) Method Names (메서드 이름) and Instance Variables (인스턴스 변수)
Function naming 규칙(8)을 사용.
(11) Constants (상수)
상수는 module level에서 정의되고, 언더스코어로 구분되어 대문자로 작성됨.
- e.g. MAX_OVERFLOW, TOTAL
(12) Designing for Inheritance
4) Public and Internal Interfaces
7. Programming Recommendations
파이썬의 다른 인터프리터 (PyPy, Jython, IronPython, Cython, Psyco 등,) 에 불리하지 않은 방법으로 코드가 작성되어야 함.
- e.g. a += b or a = a+b 형식의 명령문에 대한 CPython의 내부 문자열 연결의 효율적인 구현에 의존해서는 안됨. 이 최적화는 CPython에서 일부 유형에서만 작동함으로 취약하며,refcounting을 사용하지 않는 구현에서는 전혀 존재하지 않음.
- 라이브러리의 성능에 민감한 부분에서는 ''.join() 형태를 대신 사용해야 함.
None 과 같은 개체에 대한 비교는 equality operator (=) 가 아니라, 반드시 is 혹은 is not 과 함께 수행되어야 함.
- 'if x is not None' 을 사용할 때 'if x'로 작성하지 않도록 주의.
- 다른 값은 boolean context에서 false 가 될 수 있는 타입을 가짐.
Not .. is 보다는 Is not 오퍼레이터를 사용.
- 두 표현식은 기능적으로 같으나, is not이 가독성이 더 좋음.
# Correct:
if foo is not None:
# Wrong:
if not foo is None:
순서 지정 연산을 구현할 때
- 특정 코드만 사용하는 대신
- 6가지 연산 (__eq__, __ne__, __lt__, __le__, __gt__, __ge__) 을 모두 구현하는 것이 좋음.
- 위와 관련되어 투입되는 시간과 노력을 최소화하기 위해, functools.total_ordering() decorator가 제공됨.
- PEP 207은 reflexivity(반사성) 규칙이 파이썬에 적용됨을 나타냄. 즉, y>x -> y<x, x == y -> x!=y 의 인수로 서로 바꿀 수 있음.
- sort() 및 min() 연산은 < 연산자를 사용하도록 보장되며, max() 연산은 > 연산을 사용하도록 보장됨.
- 그러나, 다른 상항에서 혼동이 발생하지 않도록 6가지 작업을 모두 구현하는 것이 가장 좋음.
람다 표현식을 식별자에 직접 바운드 하는 할당문 대신에 def 문을 사용하도록 함.
- 일반적으로, 문자열 표현과 traceback에 유용함.
- def 사용은 람다 표현식이 제공하는 구문보다 더 많은 표현식이 가능함.
# Correct:
def f(x): return 2*x
# Wrong:
f = lambda x: 2*x
BaseException 보다는 Exception으로부터 예외를 얻도록 함.
- BaseException 은 거의 항상 잘못되는 경우를 위해 남아있음. (최후의 예외 처리를 의미하는 듯)
예외가 발생하는 위치가 아니라, 예외를 잡는 코드가 필요한 구문을 기반으로 예외 체계를 설계해야 함.
- Aim to answer the question "What went wrong" (무엇이 문제로 이끄는가) programmactically, rather than the locations where the exceptions are raised.
예외 클래스에 Error 접미사를 더하더라도, 클래스 naming 작성 규칙을 적용함.
- 6장의 exception names 와 같은 내용임
- non-local flow 혹은 다른 형태의 시그널링에 사용되는 에러가 없는 예외는 접두사를 붙일 필요 없음.
예외 체인 (exception chaining)을 적절히 사용함.
- python3 에서, 'raise X from Y'는 original traceback을 잃어버리지 않고, explicit replacement를 나타낼 때 사용됨.
- 의도적으로 내부 예외가 교체될 때 (python 2에서는 'raise X'를 사용했는데, python3에서는 'raise X from None' 으로 사용) 관련 세부 사항이 새로운 예외로 전송되는지 확인.
python2 에서 예외가 나타날 때, "raise ValueError, 'message'" 와 같이 오래된 형태보다는, "raise ValueError('message')"를 사용하도록 함.
- 전자의 경우 python3 문법상 맞지 않음.
- paren-using 형식은 예외 독립변수가 길거나, 문자열 포맷을 포함하고 있을 때, 포함하고 있는 괄호 덕에 연속 문자를 사용할 필요가 없다는 의미.
예외를 선정할 때, 가능하면 except: 를 사용하는 것보단 특정한 예외를 언급하도록 함.
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
bare except
- SystemExit, KeyboardInterrupt 예외: Control-C를 사용하여 프로그램을 중단시키는 것을 어렵게 만듦.
- bare except (=BaseException:): 절은 SystemExit, KeyboardInterrupt 예외를 잡을 수 있고, 다른 문제를 숨길 수 있음.
- 만약 사용자가 모든 예외를 잡길 원한다면, except Exception: 을 사용하도록 함.
가장 좋은 규칙은 아래 2 case에서 bare 'except' 구문의 사용을 제한하는 것
- 만약 예외 핸들러가 traceback이나 logging을 출력한다면, 사용자는 최소한 에러가 났다는 것을 알 것임.
- 만약 코드에 정리 작업이 필요하지만, raise 구문으로 뒤로 나아가지 못한다면, try...finally가 이런 케이스를 다루기 위해서는 더 나은 방법임.
이름에 대해 발견된 예외를 binding 할 때, python 2.6에서 추가된 explicit name binding 문법을 선호함.
- 이는 python3 에서만 지원되는 문법이고, 오래된 콤마 기반 구문과 연관된 애매한 문제들을 피할 수 있음.
try:
process_data()
except Exception as exc:
raise DataProcessingFailedError(str(exc))
작동 시스템 에러(operating system errors)를 잡을 때, errno 값의 introspection을 통해, python 3.3에서는 explicit 예외 계층을 선호하도록 함.
모든 try/except 구문에 대해, try 구문의 절대적인 수를 최소한으로 제한하도록 함.
# Correct:
try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
# Wrong:
try:
# Too broad!
return handle_value(collection[key])
except KeyError:
# Will also catch KeyError raised by handle_value()
return key_not_found(key)
리소스가 코드의 특정한 섹션에 위치할 때, 이것이 사용 이후에 즉시 정리되는 것을 보장하도록 'with' 구문을 사용하도록 하거나, 혹은 try/finally 구문을 적용함.
리소스를 얻거나 제공할 때를 제외하고는, 어떤 것을 할 때에는 별도의 함수, 혹은 메서드를 통해 context manager가 호출되어야 함.
# Correct:
with conn.begin_transaction():
do_stuff_in_transaction(conn)
# Wrong:
with conn:
do_stuff_in_transaction(conn)
return 구문
- return 구문에서 일관성을 유지하도록 함.
- 함수에 있는 모든 return 구문은 반드시 표현식을 반환하거나, None을 반환해야 함.
- 만약 어떤 return 구문이 표현식을 반환했다면, 어떤 return 구문이 없는 곳에서는 'return None' 을 명시하고, 함수의 끝에서 explicit return 구문이 존재해야 함.
# 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)
# Wrong:
def foo(x):
if x >= 0:
return math.sqrt(x)
def bar(x):
if x < 0:
return
return math.sqrt(x)
문자열 module 대신에, 문자열 method를 사용하도록 함.
- 문자열 method는 항상 빠르고, 유니코드 문자열을 사용하기 때문에 같은 API를 공유함.
- 만약 python 2.0 보다 더 오래된 이전 버전과의 호환성이 요구된다면, 이를 무시하도록 함.
접두사, 접미사를 비교할 때는 string slicing을 사용하지 말고, startswith(), endswith()를 사용하는 것이 의미상 명확함.
# Correct:
if foo.startswith('bar'):
# Wrong:
if foo[:3] == 'bar':
Object의 타입을 비교할 때는 직접 비교하기보다 isinstance()를 사용하는 것이 좋음.
# Correct:
if isinstance(obj, int):
# Wrong:
if type(obj) is type(1):
Object가 문자열 (str) 인지 확인할 때는, 이것이 유니코드 문자열임을 명심.
- (python2) str과 유니코드는 공통 베이스 클래스 (basestring)을 가짐.
- (python3) 유니코드, basestring은 더 이상 존재하지 않으며, 오직 str만 존재함. bytes object는 더 이상 string 계열이 아님.
if isinstance(obj, basestring):
문자열, 리스트, 튜플 등이 비어있는지 체크하려면 len을 사용하지 말고, if에 직접 넣어 확인.
# Correct:
if not seq:
if seq:
# Wrong:
if len(seq):
if not len(seq):
상당한 후행공백에 의존하는 문자열은 작성하지 않음.
- 후행공백 (trailing whitespace) 은 시각적으로 구분되지 않고, 몇몇의 에디터들에 의해 제거될 수 있음.
boolean value는 True, False, == 와 비교하여 사용하지 않음.
# Correct:
if greeting:
# Wrong:
if greeting == True:
# Wrong (Worse):
if greeting is True:
1) Function Annotations
PEP 484를 활용하면, 함수 주석에 대한 스타일 규칙은 바뀜.
이전 버전과 호환성을 위해, python3 에서 함수주석은 PEP 484 문법을 사용하는 것이 권장됨.
해당 PEP에서 추천되었던 주석 스타일은 더 이상 권장되지 않음.
다만, stdlib 밖에서는, PEP484의 규칙 내에서의 실험은 현재 권장됨.
- e.g. PEP 484 스타일 주석을 사용하는 third party library, 혹은 application을 마크업하는 것과, 쉽게 주석을 리뷰하는 것, 그들의 존재 여부를 관찰하는 것은 코드에 대한 이해도를 개선시킴.
파이썬 표준 라이브러리는 위의 주석을 시도하는 것에 보수적임.
다른 형태의 함수 주석을 만들기를 원하는 코드에 대해서는 아래와 같은 형태의 주석을 달아 놓는 것이 권장됨.
- 파일의 가장 위 부근에서 선언됨으로써, type checker 가 모든 주석을 무시하도록 함.
# type: ignore
Type checker는 선택사항이며, 별도의 툴.
- 기본 파이썬 인터프리터는 타입 확인해 의한 어떤 메시지도 발행하지 않으며, 주석에 기반하여 코드를 수정해서는 안됨.
- 사용자가 type checker를 사용하지 않는 것을 원하지 않는다면, 이는 사용자의 자유임.
- 그러나, third party library package들이 type checker를 사용하는 것이 예상되며, 이런 목적에 대해서는 PEP484 stub 파일의 사용을 추천함.
- 이전 버전과의 호환성이 필요한 코드에 대해서는, 주석 (comment) 형태의 타입 주석 (annotation)이 추가될 수 있고, PEP 484의 관련된 섹션을 참고
2) Variable Annotations
PEP 526은 변수 주석을 소개하는 문서임. 변수에 대한 스타일 권장사항은 위에 설명된 함수 주석과 유사함.
- module level variables, class and instance variables, and local variables 는 콜론 뒤에 단일 공백을 가져야 함.
- 콜론 전에는 스페이스가 없음.
- 오른쪽에 할당 되었다면, 그 때에의 equality sign은 양쪽에 하나의 스페이스를 가져야 함.
# Correct:
code: int
class Point:
coords: Tuple[int, int]
label: str = '<unknown>'
# Wrong:
code:int # No space after colon
code : int # Space before colon
class Test:
result: int=0 # No spaces around equality sign
PEP 526이 python 3.6에 허가 되었음에도 불구하고, 변수 주석 문법은 python의 모든 버전으 stub에서 선호되는 문법임 (PEP 484 참고).
End.