[Active] PEP 8 - Style Guide for Python Code
원문 링크: PEP 8 - Style Guide for Python Code
상태: Active 유형: Process 작성일: 05-Jul-2001
PEP 8 – Python 코드 스타일 가이드 번역 및 요약
서론
이 문서는 메인 Python 배포판의 표준 라이브러리를 구성하는 Python 코드에 대한 코딩 컨벤션(Coding Conventions)을 제공합니다. 이는 C로 구현된 Python 코드의 스타일 가이드라인을 설명하는 정보성 동반 PEP(PEP 7)와 함께, 코드의 가독성을 높이고 Python 코드 전반에 걸쳐 일관성을 유지하는 것을 목표로 합니다.
이 가이드는 Guido van Rossum의 원래 Python 스타일 가이드 에세이와 Barry Warsaw의 스타일 가이드 내용을 바탕으로 PEP 257 (Docstring Conventions)과 함께 채택되었습니다. 시간의 흐름과 언어 자체의 변화에 따라 새로운 컨벤션이 추가되거나 기존 컨벤션이 구식이 되면서 스타일 가이드는 계속 발전합니다.
많은 프로젝트는 자체적인 코딩 스타일 가이드라인을 가지고 있으며, 충돌이 발생하는 경우 프로젝트별 가이드가 우선합니다.
어리석은 일관성은 소심한 자의 도깨비 (A Foolish Consistency is the Hobgoblin of Little Minds)
Guido의 핵심 통찰 중 하나는 코드가 작성되는 것보다 훨씬 더 자주 읽힌다는 것입니다. 이 가이드라인은 코드의 가독성을 향상하고, 다양한 Python 코드 전반에 걸쳐 일관성을 유지하기 위해 고안되었습니다. PEP 20이 말하듯이, “가독성이 중요합니다(Readability counts).”
스타일 가이드는 일관성에 관한 것입니다. 이 스타일 가이드와의 일관성도 중요하지만, 프로젝트 내에서의 일관성이 더 중요하고, 하나의 모듈(Module)이나 함수(Function) 내에서의 일관성이 가장 중요합니다.
하지만 언제 일관성을 유지하지 말아야 할지 아는 것도 중요합니다. 때로는 스타일 가이드 권장 사항이 적용되지 않을 수도 있습니다. 의심스러울 때는 최선의 판단을 내리고, 다른 예시들을 참고하여 가장 적절한 것을 선택하세요. 또한, 질문하는 것을 주저하지 마세요! 특히, 이 PEP를 준수하기 위해 하위 호환성(Backwards compatibility)을 깨뜨리지 마세요.
특정 가이드라인을 무시해야 할 다른 좋은 이유들은 다음과 같습니다.
- 가이드라인을 적용했을 때, PEP를 따르는 코드를 읽는 데 익숙한 사람에게조차 코드가 덜 가독성 있게 되는 경우.
- 주변 코드가 (역사적인 이유 등으로) 이미 가이드라인을 어기고 있어 일관성을 유지해야 하는 경우. (하지만 이는 다른 사람의 혼란을 정리할 좋은 기회가 될 수도 있습니다.)
- 해당 코드가 가이드라인 도입 이전에 작성되었고, 코드를 수정할 다른 이유가 없는 경우.
- 코드가 스타일 가이드에서 권장하는 기능을 지원하지 않는 이전 버전의 Python과 호환되어야 하는 경우.
코드 레이아웃 (Code Lay-out)
들여쓰기 (Indentation)
들여쓰기 수준당 4개의 공백을 사용합니다.
줄 바꿈(Continuation lines)은 괄호, 대괄호, 중괄호 내에서 Python의 암시적 줄 연결(implicit line joining)을 사용하여 요소를 수직으로 정렬하거나, 내어쓰기(hanging indent)를 사용해야 합니다. 내어쓰기를 사용할 때는 다음을 고려해야 합니다. 첫 줄에 인자(argument)가 없어야 하며, 후속 들여쓰기는 연속 줄임을 명확히 구분할 수 있도록 더 깊게 해야 합니다.
예시:
# 올바른 예시:
# 여는 구분 기호와 정렬.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 인자를 나머지 부분과 구별하기 위해 4개의 공백(추가 들여쓰기 수준)을 추가.
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# 내어쓰기는 한 수준을 추가해야 함.
foo = long_function_name(
var_one, var_two,
var_three, var_four)
# 잘못된 예시:
# 수직 정렬을 사용하지 않을 때 첫 줄에 인자 금지.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 들여쓰기가 구별되지 않으므로 추가 들여쓰기 필요.
def long_function_name(
var_one, var_two,
var_three, var_four):
print(var_one)
if 문의 조건부가 여러 줄에 걸쳐 길어질 경우, if
와 공백, 그리고 여는 괄호의 조합은 다음 줄에 자연스러운 4칸 들여쓰기를 만듭니다. 이는 if
문 내부에 중첩된 코드 블록의 4칸 들여쓰기와 시각적으로 충돌할 수 있습니다. PEP 8은 이러한 조건부 줄을 내부 코드 블록과 시각적으로 구별하는 방법에 대해 명확한 입장을 취하지 않습니다. 허용되는 방법으로는 추가 들여쓰기 없음, 주석 추가, 조건부 연속 줄에 추가 들여쓰기 등이 있습니다.
여러 줄로 된 구성에서 닫는 중괄호/대괄호/괄호는 목록의 마지막 줄에서 첫 번째 공백이 아닌 문자 아래에 정렬될 수 있거나, 여러 줄 구성이 시작되는 줄의 첫 번째 문자 아래에 정렬될 수 있습니다.
탭(Tabs) 또는 공백(Spaces)?
공백이 선호되는 들여쓰기 방식입니다. 탭은 이미 탭으로 들여쓰기된 코드와의 일관성을 유지하기 위해서만 사용해야 합니다. Python은 들여쓰기를 위해 탭과 공백을 섞어 사용하는 것을 허용하지 않습니다.
최대 줄 길이 (Maximum Line Length)
모든 줄은 최대 79자(characters)로 제한해야 합니다. 구조적 제약이 적은 긴 텍스트 블록(Docstrings 또는 주석)의 경우, 줄 길이는 72자로 제한해야 합니다.
줄 길이를 제한하면 여러 파일을 나란히 열 수 있으며, 두 버전을 인접한 열에 표시하는 코드 검토 도구를 사용할 때 유용합니다. 대부분의 도구에서 기본적으로 줄바꿈(wrapping)은 코드의 시각적 구조를 방해하여 이해하기 어렵게 만듭니다.
일부 팀은 더 긴 줄 길이를 선호할 수 있습니다. 이 문제에 대해 합의에 도달할 수 있는 팀이 전적으로 또는 주로 유지 관리하는 코드의 경우, 주석과 Docstrings가 여전히 72자로 줄바꿈된다는 조건 하에 줄 길이 제한을 99자까지 늘려도 괜찮습니다. Python 표준 라이브러리는 보수적이며, 줄 길이를 79자(Docstrings/주석은 72자)로 제한해야 합니다.
긴 줄을 래핑(wrapping)하는 선호되는 방법은 괄호, 대괄호, 중괄호 내부의 Python 암시적 줄 연결을 사용하는 것입니다. 표현식을 괄호로 묶어 긴 줄을 여러 줄로 나눌 수 있습니다. 이는 줄 연결을 위해 백슬래시(\
)를 사용하는 것보다 선호됩니다. 백슬래시가 적절한 경우도 있습니다. 예를 들어, Python 3.10 이전에는 긴 with
문에서 암시적 줄 연결을 사용할 수 없었으므로, 이 경우에는 백슬래시가 허용되었습니다.
이항 연산자 앞 또는 뒤에서 줄을 끊어야 하는가? (Should a Line Break Before or After a Binary Operator?)
수십 년 동안 권장되는 스타일은 이항 연산자 뒤에서 줄을 끊는 것이었습니다. 하지만 이는 두 가지 방식으로 가독성을 해칠 수 있습니다. 연산자가 화면의 다른 열에 흩어지는 경향이 있고, 각 연산자가 피연산자로부터 멀어져 이전 줄로 이동합니다.
수학자들과 출판사들은 이 가독성 문제를 해결하기 위해 반대되는 규칙을 따릅니다. Donald Knuth는 그의 Computers and Typesetting
시리즈에서 전통적인 규칙을 설명합니다. “문단 내의 수식은 항상 이항 연산 및 관계 뒤에서 줄을 끊지만, 표시되는 수식은 항상 이항 연산 앞에서 줄을 끊습니다.”
수학의 전통을 따르는 것이 일반적으로 더 읽기 쉬운 코드를 만듭니다. Python 코드에서는 이항 연산자 앞이나 뒤에서 줄을 끊을 수 있지만, 해당 로컬 컨벤션이 일관되어야 합니다. 새로운 코드에는 Knuth의 스타일이 권장됩니다.
빈 줄 (Blank Lines)
최상위 함수(Top-level function) 및 클래스(Class) 정의는 두 개의 빈 줄로 둘러쌉니다. 클래스 내의 메서드(Method) 정의는 하나의 빈 줄로 둘러쌉니다. 관련된 함수 그룹을 구분하기 위해 추가 빈 줄을 (드물게) 사용할 수 있습니다. 관련된 짧은 한 줄 코드(예: 더미 구현 세트) 사이에는 빈 줄을 생략할 수 있습니다. 함수 내에서는 논리적 섹션을 구분하기 위해 빈 줄을 드물게 사용합니다.
소스 파일 인코딩 (Source File Encoding)
핵심 Python 배포판의 코드는 항상 UTF-8을 사용해야 하며, 인코딩 선언을 포함해서는 안 됩니다. 표준 라이브러리에서는 테스트 목적으로만 비-UTF-8 인코딩을 사용해야 합니다. 비-ASCII 문자는 드물게 사용하고, 가급적 장소나 인명 표기에만 사용하세요. Python 표준 라이브러리의 모든 식별자(identifier)는 ASCII 전용 식별자를 사용해야 하며, 가능한 경우 영어 단어를 사용해야 합니다 (많은 경우 약어 및 기술 용어가 사용됨). 전 세계 사용자를 대상으로 하는 오픈 소스 프로젝트도 유사한 정책을 채택하는 것이 권장됩니다.
임포트 (Imports)
import
문은 일반적으로 개별 줄에 있어야 합니다.
# 올바른 예시:
import os
import sys
# 잘못된 예시:
import sys, os
하지만 다음은 허용됩니다.
# 올바른 예시:
from subprocess import Popen, PIPE
import
문은 항상 파일의 맨 위에, 모듈 주석과 Docstrings 바로 뒤, 모듈 전역 변수와 상수 앞에 배치됩니다.
import
문은 다음 순서로 그룹화해야 합니다.
- 표준 라이브러리
import
s. - 관련된 서드파티
import
s. - 로컬 애플리케이션/라이브러리 특정
import
s.
각 import
그룹 사이에 빈 줄을 넣어야 합니다.
절대 경로 임포트(Absolute imports)가 권장됩니다. 일반적으로 더 읽기 쉽고, 임포트 시스템이 잘못 구성된 경우 더 잘 작동하거나 (최소한 더 나은 오류 메시지를 제공합니다).
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
그러나 명시적 상대 경로 임포트(Explicit relative imports)는 복잡한 패키지 레이아웃을 다룰 때 절대 경로 임포트가 불필요하게 장황해지는 경우 허용 가능한 대안입니다.
from . import sibling
from .sibling import example
표준 라이브러리 코드는 복잡한 패키지 레이아웃을 피하고 항상 절대 경로 임포트를 사용해야 합니다.
클래스를 포함하는 모듈에서 클래스를 임포트할 때, 다음 표기법은 일반적으로 괜찮습니다.
from myclass import MyClass
from foo.bar.yourclass import YourClass
만약 이 표기법이 로컬 이름 충돌(name clashes)을 일으킨다면, 명시적으로 다음과 같이 표기합니다.
import myclass
import foo.bar.yourclass
그리고 myclass.MyClass
와 foo.bar.yourclass.YourClass
를 사용합니다.
와일드카드 임포트(from <module> import *
)는 네임스페이스에 어떤 이름이 있는지 불분명하게 만들고, 독자와 많은 자동화 도구를 혼란스럽게 하므로 피해야 합니다. 와일드카드 임포트의 한 가지 정당한 사용 사례는 내부 인터페이스를 공개 API의 일부로 재배포하는 경우입니다.
모듈 수준 “던더(Dunder)” 이름 (Module Level Dunder Names)
__all__
, __author__
, __version__
등과 같은 모듈 수준의 “던더(Dunder)” (선행 및 후행 밑줄 두 개가 있는 이름)는 모듈 Docstring 뒤에 오지만, from __future__
임포트를 제외한 모든 import
문 앞에 배치해야 합니다. Python은 future-imports
가 Docstrings를 제외한 다른 모든 코드보다 먼저 모듈에 나타나야 한다고 규정합니다.
"""이것은 예시 모듈입니다. 이 모듈은 작업을 수행합니다."""
from __future__ import barry_as_FLUFL
__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
import os
import sys
문자열 인용 부호 (String Quotes)
Python에서 작은따옴표('
)로 묶인 문자열과 큰따옴표("
)로 묶인 문자열은 동일합니다. 이 PEP는 이에 대한 권장 사항을 제공하지 않습니다. 규칙을 선택하고 그것을 따르세요. 그러나 문자열에 작은따옴표나 큰따옴표 문자가 포함된 경우, 백슬래시(\
)를 피하기 위해 다른 인용 부호를 사용하세요. 이것은 가독성을 향상시킵니다.
세 개의 인용 부호("""
또는 '''
)로 묶인 문자열의 경우, PEP 257의 Docstring 컨벤션과 일관성을 유지하기 위해 항상 큰따옴표("""
)를 사용하세요.
표현식 및 문장의 공백 (Whitespace in Expressions and Statements)
사소한 불평들 (Pet Peeves)
다음 상황에서는 불필요한 공백을 피하세요.
- 괄호, 대괄호 또는 중괄호 바로 안쪽:
# 올바른 예시: spam(ham[1], {eggs: 2}) # 잘못된 예시: spam( ham[ 1 ], { eggs: 2 } )
- 뒤따르는 쉼표와 닫는 괄호 사이:
# 올바른 예시: foo = (0,) # 잘못된 예시: bar = (0, )
- 쉼표, 세미콜론 또는 콜론 바로 앞:
# 올바른 예시: if x == 4: print(x, y); x, y = y, x # 잘못된 예시: if x == 4 : print(x , y) ; x , y = y , x
단, 슬라이스(slice)에서 콜론은 이항 연산자처럼 작동하며 양쪽에 동일한 양의 공백이 있어야 합니다 (가장 낮은 우선순위의 연산자로 취급). 확장된 슬라이스에서는 두 콜론 모두 동일한 양의 간격을 적용해야 합니다. 예외: 슬라이스 매개변수가 생략되면 공백도 생략됩니다.
- 함수 호출의 인자 목록을 시작하는 여는 괄호 바로 앞:
# 올바른 예시: spam(1) # 잘못된 예시: spam (1)
- 인덱싱 또는 슬라이싱을 시작하는 여는 괄호 바로 앞:
# 올바른 예시: dct['key'] = lst[index] # 잘못된 예시: dct ['key'] = lst [index]
- 할당(또는 기타) 연산자 주변에 두 개 이상의 공백을 사용하여 다른 것과 정렬하는 것:
# 올바른 예시: x = 1 y = 2 long_variable = 3 # 잘못된 예시: x = 1 y = 2 long_variable = 3
기타 권장 사항 (Other Recommendations)
어디에서든 후행 공백(trailing whitespace)을 피하세요.
항상 이항 연산자(=
, +=
, -=
, ==
, <
, >
, !=
, <=
, >=
, in
, not in
, is
, is not
, and
, or
, not
) 양쪽에 하나의 공백을 두세요.
우선순위가 다른 연산자가 사용되는 경우, 가장 낮은 우선순위의 연산자 주위에 공백을 추가하는 것을 고려하세요.
함수 어노테이션(Function annotations)은 콜론에 대한 일반 규칙을 사용해야 하며, ->
화살표가 있는 경우 항상 그 주위에 공백을 두어야 합니다.
키워드 인자(keyword argument)나 어노테이션이 없는 함수 매개변수의 기본값을 나타낼 때 사용되는 =
기호 주위에는 공백을 사용하지 마세요.
그러나 인자 어노테이션과 기본값을 결합할 때는 =
기호 주위에 공백을 사용하세요.
# 올바른 예시:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
# 잘못된 예시:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...
복합 문장(Compound statements, 즉 같은 줄에 여러 문장)은 일반적으로 권장되지 않습니다.
# 올바른 예시:
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
후행 쉼표(Trailing Commas) 사용 시점
후행 쉼표는 일반적으로 선택 사항이지만, 요소가 하나인 튜플(tuple)을 만들 때는 필수입니다. 명확성을 위해 후자는 (기술적으로는 불필요하지만) 괄호로 둘러싸는 것이 권장됩니다.
# 올바른 예시:
FILES = ('setup.cfg',)
# 잘못된 예시:
FILES = 'setup.cfg',
후행 쉼표가 불필요할 때도, 버전 관리 시스템을 사용하거나 값, 인자 또는 임포트된 항목 목록이 시간이 지남에 따라 확장될 것으로 예상될 때 유용합니다. 이 패턴은 각 값을 별도의 줄에 놓고 항상 후행 쉼표를 추가하며, 다음 줄에 닫는 괄호/대괄호/중괄호를 추가하는 것입니다.
주석 (Comments)
코드와 모순되는 주석은 주석이 없는 것보다 나쁩니다. 코드가 변경될 때 항상 주석을 최신 상태로 유지하는 것을 최우선으로 하세요!
주석은 완전한 문장이어야 합니다. 첫 단어는 소문자로 시작하는 식별자가 아닌 한 대문자로 시작해야 합니다. 블록 주석(Block comments)은 일반적으로 완전한 문장으로 구성된 하나 이상의 단락으로 이루어지며, 각 문장은 마침표로 끝납니다. 여러 문장으로 된 주석에서는 마지막 문장 뒤를 제외하고 문장 끝 마침표 뒤에 한두 칸의 공백을 사용해야 합니다.
비영어권 Python 개발자: 코드를 읽을 사람이 모국어를 사용하지 않을 것이라고 120% 확신하지 않는 한, 주석을 영어로 작성하세요.
블록 주석 (Block Comments)
블록 주석은 일반적으로 뒤따르는 코드의 일부(또는 전부)에 적용되며, 해당 코드와 동일한 수준으로 들여쓰기됩니다. 블록 주석의 각 줄은 #
와 하나의 공백으로 시작합니다 (주석 내부에 들여쓰기된 텍스트가 아닌 경우). 블록 주석 내의 단락은 단일 #
을 포함하는 줄로 구분됩니다.
인라인 주석 (Inline Comments)
인라인 주석(Inline comments)은 드물게 사용하세요.
인라인 주석은 문장과 같은 줄에 있는 주석입니다. 인라인 주석은 문장에서 최소 두 칸의 공백으로 분리되어야 합니다. #
와 하나의 공백으로 시작해야 합니다.
뻔한 내용을 설명하는 인라인 주석은 불필요하며 실제로는 방해가 됩니다.
# 이렇게 하지 마세요:
x = x + 1 # x를 1 증가시킴
# 하지만 이런 경우는 유용합니다:
x = x + 1 # 경계값을 보정
Docstrings (Documentation Strings)
좋은 Docstrings를 작성하는 컨벤션은 PEP 257에 명시되어 있습니다.
모든 공용 모듈, 함수, 클래스 및 메서드에 Docstrings를 작성하세요. 비공용 메서드에는 Docstrings가 필요하지 않지만, 메서드가 무엇을 하는지 설명하는 주석을 작성해야 합니다. 이 주석은 def
줄 뒤에 나타나야 합니다. PEP 257은 좋은 Docstring 컨벤션을 설명합니다. 가장 중요한 것은 여러 줄 Docstring을 끝내는 """
가 자체 줄에 있어야 한다는 것입니다.
"""foobang을 반환합니다.
선택적 plotz는 bizbaz를 먼저 frobnicate하라고 말합니다.
"""
한 줄 Docstrings의 경우, 닫는 """
를 같은 줄에 유지하세요.
"""전 앵무새를 반환합니다."""
명명 규칙 (Naming Conventions)
Python 라이브러리의 명명 규칙은 다소 혼란스러우므로 완전히 일관되게 만들 수는 없습니다. 하지만 현재 권장되는 명명 표준은 다음과 같습니다. 새로운 모듈과 패키지(서드파티 프레임워크 포함)는 이 표준에 따라 작성되어야 하지만, 기존 라이브러리가 다른 스타일을 가지고 있다면 내부 일관성이 선호됩니다.
최우선 원칙 (Overriding Principle)
API의 공개 부분으로 사용자에게 보이는 이름은 구현보다는 사용을 반영하는 컨벤션을 따라야 합니다.
설명: 명명 스타일 (Descriptive: Naming Styles)
다양한 명명 스타일이 있습니다. 사용 목적과 관계없이 어떤 명명 스타일이 사용되는지 인식할 수 있으면 도움이 됩니다. 일반적으로 구분되는 명명 스타일은 다음과 같습니다.
b
(단일 소문자)B
(단일 대문자)lowercase
lower_case_with_underscores
UPPERCASE
UPPER_CASE_WITH_UNDERSCORES
CapitalizedWords
(또는CapWords
,CamelCase
– 글자의 울퉁불퉁한 모양 때문에 붙여진 이름).StudlyCaps
라고도 불립니다.- 참고:
CapWords
에서 약어를 사용할 때는 약어의 모든 글자를 대문자로 표기합니다. 따라서HTTPServerError
가HttpServerError
보다 낫습니다.
- 참고:
mixedCase
(첫 글자가 소문자라는 점에서CapitalizedWords
와 다릅니다!)Capitalized_Words_With_Underscores
(보기 흉함!)
관련 이름을 함께 그룹화하기 위해 짧고 고유한 접두사를 사용하는 스타일도 있습니다. Python에서는 많이 사용되지 않지만, 완전성을 위해 언급됩니다. 예를 들어, os.stat()
함수는 전통적으로 st_mode
, st_size
, st_mtime
등과 같은 이름을 가진 튜플을 반환합니다. (이는 POSIX 시스템 호출 구조체의 필드와의 연관성을 강조하여, 해당 분야에 익숙한 프로그래머에게 도움이 됩니다.)
X11 라이브러리는 모든 공개 함수에 선행 X
를 사용합니다. Python에서는 속성(attribute) 및 메서드(method) 이름이 객체로 접두사화되고, 함수 이름이 모듈 이름으로 접두사화되기 때문에 이 스타일은 일반적으로 불필요하다고 간주됩니다.
또한, 선행 또는 후행 밑줄을 사용하는 다음 특수 형식이 인식됩니다 (이들은 일반적으로 모든 대소문자 규칙과 결합될 수 있습니다).
_single_leading_underscore
: 약한 “내부 사용” 지표입니다. 예:from M import *
는 밑줄로 시작하는 이름을 가진 객체를 임포트하지 않습니다.single_trailing_underscore_
: Python 키워드와의 충돌을 피하기 위한 관례로 사용됩니다. 예:tkinter.Toplevel(master, class_='ClassName')
.__double_leading_underscore
: 클래스 속성(class attribute)에 이름을 붙일 때, 이름 맹글링(name mangling)을 호출합니다 (클래스FooBar
내부에서__boo
는_FooBar__boo
가 됩니다).__double_leading_and_trailing_underscore__
: 사용자 제어 네임스페이스에 있는 “매직” 객체 또는 속성입니다. 예:__init__
,__import__
또는__file__
. 이러한 이름을 절대로 임의로 만들지 마세요. 문서에 따라 사용해야 합니다.
규범: 명명 규칙 (Prescriptive: Naming Conventions)
피해야 할 이름 (Names to Avoid) 단일 문자 변수 이름으로 ‘l’ (소문자 L), ‘O’ (대문자 O), ‘I’ (대문자 I)를 절대 사용하지 마세요. 일부 글꼴에서는 이 문자들이 숫자 1과 0과 구별하기 어렵습니다. ‘l’을 사용하고 싶을 때는 대신 ‘L’을 사용하세요.
ASCII 호환성 (ASCII Compatibility) 표준 라이브러리에서 사용되는 식별자는 PEP 3131의 정책 섹션에 설명된 대로 ASCII 호환이어야 합니다.
패키지(Package) 및 모듈 이름 (Module Names) 모듈은 짧고, 모두 소문자로 된 이름을 가져야 합니다. 가독성을 향상시키는 경우 모듈 이름에 밑줄을 사용할 수 있습니다. Python 패키지도 짧고, 모두 소문자로 된 이름을 가져야 하지만, 밑줄 사용은 권장되지 않습니다.
C 또는 C++로 작성된 확장 모듈(extension module)이 더 높은 수준의 (예: 객체 지향적인) 인터페이스를 제공하는 Python 모듈과 함께 제공되는 경우, C/C++ 모듈은 선행 밑줄을 가집니다 (예: _socket
).
클래스 이름 (Class Names)
클래스 이름은 일반적으로 CapWords
컨벤션을 사용해야 합니다.
인터페이스가 문서화되어 있고 주로 호출 가능(callable)한 것으로 사용되는 경우에는 함수 명명 컨벤션을 대신 사용할 수 있습니다.
타입 변수 이름 (Type Variable Names)
PEP 484에서 도입된 타입 변수의 이름은 일반적으로 CapWords
를 사용하며 짧은 이름을 선호합니다: T
, AnyStr
, Num
. 공변(covariant) 또는 반공변(contravariant) 동작을 선언하는 데 사용되는 변수에는 각각 _co
또는 _contra
접미사를 추가하는 것이 권장됩니다.
예외 이름 (Exception Names) 예외는 클래스여야 하므로, 클래스 명명 규칙이 여기에 적용됩니다. 그러나 예외 이름에는 “Error” 접미사를 사용해야 합니다 (예외가 실제로 오류인 경우).
전역 변수 이름 (Global Variable Names)
(이 변수들이 단일 모듈 내에서만 사용될 것으로 예상됩니다.) 컨벤션은 함수에 대한 것과 거의 동일합니다.
from M import *
를 통해 사용하도록 설계된 모듈은 __all__
메커니즘을 사용하여 전역 변수 노출을 방지하거나, 이러한 전역 변수에 밑줄을 접두사로 붙이는 이전 컨벤션을 사용해야 합니다 (이 전역 변수가 “모듈 비공개”임을 나타내기 위해 이렇게 할 수 있습니다).
함수 및 변수 이름 (Function and Variable Names)
함수 이름은 소문자여야 하며, 가독성을 높이기 위해 필요한 경우 단어를 밑줄로 구분합니다.
변수 이름은 함수 이름과 동일한 컨벤션을 따릅니다.
mixedCase
는 이미 해당 스타일이 지배적인 컨텍스트(예: threading.py
)에서만 허용되며, 하위 호환성을 유지하기 위함입니다.
함수 및 메서드 인자 (Function and Method Arguments)
인스턴스 메서드의 첫 번째 인자에는 항상 self
를 사용합니다.
클래스 메서드의 첫 번째 인자에는 항상 cls
를 사용합니다.
함수 인자 이름이 예약된 키워드와 충돌하는 경우, 약어나 오자(spelling corruption)를 사용하는 것보다 단일 후행 밑줄을 추가하는 것이 일반적으로 좋습니다. 따라서 class_
가 clss
보다 낫습니다. (아마도 동의어를 사용하여 충돌을 피하는 것이 더 좋습니다.)
메서드 이름 및 인스턴스 변수 (Method Names and Instance Variables)
함수 명명 규칙을 사용합니다: 소문자이며, 가독성을 높이기 위해 필요한 경우 단어를 밑줄로 구분합니다.
비공개 메서드 및 인스턴스 변수에는 하나의 선행 밑줄만 사용합니다.
하위 클래스와의 이름 충돌을 피하기 위해 Python의 이름 맹글링(name mangling) 규칙을 호출하려면 두 개의 선행 밑줄을 사용합니다.
Python은 이러한 이름을 클래스 이름과 함께 맹글링합니다. 예를 들어, 클래스 Foo
에 __a
라는 속성이 있으면 Foo.__a
로 접근할 수 없습니다. (고집스러운 사용자는 Foo._Foo__a
를 호출하여 여전히 접근할 수 있습니다.) 일반적으로 이중 선행 밑줄은 하위 클래스가 실수로 동일한 이름을 가진 속성을 포함할 경우 이름 충돌을 피하기 위해서만 사용해야 합니다.
상수 (Constants)
상수는 일반적으로 모듈 수준에서 정의되며, 모든 글자를 대문자로 쓰고 단어를 밑줄로 구분하여 작성합니다. 예시로는 MAX_OVERFLOW
와 TOTAL
이 있습니다.
상속을 위한 설계 (Designing for Inheritance) 클래스의 메서드와 인스턴스 변수 (총칭하여 “속성”)가 공개(public)인지 비공개(non-public)인지 항상 결정해야 합니다. 의심스러운 경우 비공개를 선택하세요. 나중에 공개 속성을 비공개로 만드는 것보다 비공개 속성을 공개로 만드는 것이 더 쉽습니다.
공개 속성은 클래스의 관련 없는 클라이언트가 사용하도록 예상하며, 하위 호환성이 깨지는 변경을 피하기로 약속하는 것입니다. 비공개 속성은 서드파티가 사용하도록 의도되지 않으며, 비공개 속성이 변경되거나 제거되지 않을 것이라는 보장은 없습니다. 여기서 “private”이라는 용어를 사용하지 않는 이유는 Python에서 어떤 속성도 실제로 비공개가 아니기 때문입니다 (일반적으로 불필요한 노력을 들이지 않고는).
또 다른 속성 범주는 “서브클래스 API”의 일부인 속성입니다 (다른 언어에서는 종종 “protected”라고 불림). 일부 클래스는 클래스의 동작 측면을 확장하거나 수정하기 위해 상속되도록 설계됩니다. 이러한 클래스를 설계할 때, 어떤 속성이 공개이고, 어떤 속성이 서브클래스 API의 일부이며, 어떤 속성이 기본 클래스에서만 사용되는지 명시적으로 결정해야 합니다.
이 점을 염두에 두고 다음은 Pythonic 가이드라인입니다.
- 공개 속성에는 선행 밑줄이 없어야 합니다.
- 공개 속성 이름이 예약된 키워드와 충돌하는 경우, 속성 이름에 단일 후행 밑줄을 추가하세요. 이는 약어 또는 오자보다 선호됩니다. (그러나 이 규칙에도 불구하고, 특히 클래스 메서드의 첫 번째 인자에서 클래스로 알려진 변수나 인자에는 ‘cls’가 선호되는 표기법입니다.)
간단한 공개 데이터 속성의 경우, 복잡한 접근자/변형자 메서드 없이 속성 이름만 노출하는 것이 가장 좋습니다. Python은 간단한 데이터 속성에 기능적 동작을 추가해야 할 경우를 대비하여 미래 개선을 위한 쉬운 경로를 제공한다는 점을 명심하세요. 이 경우, 속성(properties)을 사용하여 간단한 데이터 속성 접근 구문 뒤에 기능적 구현을 숨기세요.
클래스가 서브클래싱될 예정이고, 서브클래스가 사용하지 않기를 원하는 속성이 있다면, 두 개의 선행 밑줄과 후행 밑줄 없이 이름을 지정하는 것을 고려하세요. 이는 Python의 이름 맹글링 알고리즘을 호출하여 클래스 이름이 속성 이름으로 맹글링됩니다. 이는 서브클래스가 실수로 동일한 이름을 가진 속성을 포함할 경우 속성 이름 충돌을 피하는 데 도움이 됩니다.
공개 및 내부 인터페이스 (Public and Internal Interfaces)
모든 하위 호환성 보장은 공개 인터페이스에만 적용됩니다. 따라서 사용자가 공개 인터페이스와 내부 인터페이스를 명확하게 구별할 수 있어야 합니다.
문서화된 인터페이스는 문서에서 명시적으로 임시(provisional) 또는 내부 인터페이스로 선언되어 일반적인 하위 호환성 보장에서 제외되지 않는 한 공개로 간주됩니다. 문서화되지 않은 모든 인터페이스는 내부로 가정해야 합니다.
인트로스펙션(introspection)을 더 잘 지원하기 위해 모듈은 __all__
속성을 사용하여 공개 API의 이름을 명시적으로 선언해야 합니다. __all__
을 빈 목록으로 설정하는 것은 모듈에 공개 API가 없음을 나타냅니다.
__all__
이 적절하게 설정되어 있더라도, 내부 인터페이스(패키지, 모듈, 클래스, 함수, 속성 또는 기타 이름)는 여전히 단일 선행 밑줄로 접두사화되어야 합니다.
가져온 이름은 항상 구현 세부 사항으로 간주되어야 합니다. 다른 모듈은 os.path
또는 서브모듈의 기능을 노출하는 패키지의 __init__
모듈과 같이 포함하는 모듈의 API의 명시적으로 문서화된 부분이 아닌 한, 그러한 가져온 이름에 대한 간접적인 접근에 의존해서는 안 됩니다.
프로그래밍 권장 사항 (Programming Recommendations)
코드는 다른 Python 구현(PyPy, Jython, IronPython, Cython, Psyco 등)에 불이익을 주지 않는 방식으로 작성되어야 합니다.
예를 들어, a += b
또는 a = a + b
형식의 문장에 대한 CPython의 효율적인 In-place 문자열 연결 구현에 의존하지 마세요. 이 최적화는 CPython에서도 취약하며 (일부 유형에서만 작동), Refcounting을 사용하지 않는 구현에서는 전혀 존재하지 않습니다. 성능에 민감한 라이브러리 부분에서는 대신 ''.join()
형식을 사용해야 합니다.
None
과 같은 싱글턴(singletons)과의 비교는 항상 is
또는 is not
으로 해야 하며, 절대로 동등 연산자(==
, !=
)를 사용해서는 안 됩니다.
또한 if x is not None
을 의미할 때 if x
를 작성하지 않도록 주의하세요. 예를 들어, 기본값이 None
인 변수나 인자가 다른 값으로 설정되었는지 테스트할 때 그렇습니다. 다른 값은 부울(boolean) 컨텍스트에서 False
일 수 있는 유형(예: 컨테이너)을 가질 수 있습니다!
not ... is
대신 is not
연산자를 사용하세요.
# 올바른 예시:
if foo is not None:
# 잘못된 예시:
if not foo is None:
풍부한 비교(rich comparisons)로 순서 지정 연산을 구현할 때는 특정 비교만 수행하는 다른 코드에 의존하기보다는 여섯 가지 모든 연산(__eq__
, __ne__
, __lt__
, __le__
, __gt__
, __ge__
)을 구현하는 것이 가장 좋습니다.
람다 표현식을 식별자에 직접 바인딩하는 할당문 대신 항상 def
문을 사용하세요.
# 올바른 예시:
def f(x): return 2*x
# 잘못된 예시:
f = lambda x: 2*x
예외는 BaseException
대신 Exception
에서 파생시키세요. BaseException
에서 직접 상속하는 것은 거의 항상 잘못된 예외를 잡는 경우에만 예약됩니다.
예외를 잡을 때, bare except:
절을 사용하는 대신 가능한 한 특정 예외를 명시하세요. bare except:
절은 SystemExit
및 KeyboardInterrupt
예외를 잡아서 Ctrl-C로 프로그램을 중단하기 어렵게 만들고 다른 문제를 숨길 수 있습니다.
리소스가 코드의 특정 섹션에 로컬(local)한 경우, with
문을 사용하여 사용 후 즉시 안정적으로 정리되도록 하세요. try/finally
문도 허용됩니다. 컨텍스트 관리자(context manager)는 리소스 획득 및 해제 외의 다른 작업을 수행하는 경우 별도의 함수 또는 메서드를 통해 호출해야 합니다.
return
문은 일관성 있게 사용하세요. 함수 내의 모든 return
문은 표현식(expression)을 반환하거나, 아무것도 반환하지 않아야 합니다. 만약 어떤 return
문이 표현식을 반환한다면, 값이 반환되지 않는 return
문은 명시적으로 return None
으로 선언해야 하며, 함수의 끝(도달 가능하다면)에도 명시적인 return
문이 있어야 합니다.
접두사 또는 접미사를 확인하려면 문자열 슬라이싱 대신 ''.startswith()
및 ''.endswith()
를 사용하세요. startswith()
및 endswith()
는 더 깔끔하고 오류 발생 가능성이 적습니다.
객체 유형 비교는 항상 isinstance()
를 사용해야 하며, 유형을 직접 비교하는 것은 피해야 합니다.
시퀀스(문자열, 리스트, 튜플)의 경우, 빈 시퀀스가 False
임을 이용하세요.
# 올바른 예시:
if not seq:
if seq:
# 잘못된 예시:
if len(seq):
if not len(seq):
중요한 후행 공백에 의존하는 문자열 리터럴을 작성하지 마세요. 그러한 후행 공백은 시각적으로 구별하기 어렵고 일부 편집기(또는 최근에는 reindent.py
)는 이를 제거합니다. 부울(boolean) 값을 True
또는 False
와 ==
를 사용하여 비교하지 마세요.
함수 어노테이션 (Function Annotations)
PEP 484가 채택되면서 함수 어노테이션의 스타일 규칙이 변경되었습니다. 함수 어노테이션은 PEP 484 구문을 사용해야 합니다. (이전 섹션에 어노테이션에 대한 몇 가지 서식 권장 사항이 있습니다.) 이전에 이 PEP에서 권장했던 어노테이션 스타일 실험은 더 이상 권장되지 않습니다. 그러나 표준 라이브러리 외부에서는 PEP 484 규칙 내에서의 실험이 이제 권장됩니다.
변수 어노테이션 (Variable Annotations)
PEP 526은 변수 어노테이션을 도입했습니다. 이에 대한 스타일 권장 사항은 위에서 설명한 함수 어노테이션과 유사합니다. 모듈 수준 변수, 클래스 및 인스턴스 변수, 그리고 지역 변수에 대한 어노테이션은 콜론 뒤에 하나의 공백이 있어야 합니다. 콜론 앞에는 공백이 없어야 합니다. 할당문에 우변이 있는 경우, 등호 양쪽에 정확히 하나의 공백이 있어야 합니다.
# 올바른 예시:
code: int
class Point:
coords: Tuple[int, int]
label: str = '<unknown>'
# 잘못된 예시:
code:int # 콜론 뒤에 공백 없음
code : int # 콜론 앞에 공백 있음
class Test:
result: int=0 # 등호 주위에 공백 없음
PEP 526은 Python 3.6에 채택되었지만, 변수 어노테이션 구문은 모든 버전의 Python에서 스텁 파일(stub files)에 대해 선호되는 구문입니다 (자세한 내용은 PEP 484 참조).
⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.
Comments