Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 8 – Python 코드 스타일 가이드

Author:
Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>, Alyssa Coghlan <ncoghlan at gmail.com>
Status:
Active
Type:
Process
Created:
05-Jul-2001
Post-History:
05-Jul-2001, 01-Aug-2013

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

소개

이 문서는 메인 Python 배포판의 표준 라이브러리를 구성하는 Python 코드의 코딩 규칙을 제시합니다. 함께 제공되는 정보성 PEP인 파이썬 C 구현의 C 코드를 위한 스타일 지침을 참고하십시오.

이 문서와 PEP 257 (독스트링 규칙)은 Guido의 원래 Python 스타일 가이드 에세이를 바탕으로 하였으며, Barry의 스타일 가이드 [2]에서 일부 내용을 추가하였습니다.

이 스타일 가이드는 새로운 규약이 확인되고 언어 자체의 변화로 과거의 규약이 쓸모없어짐에 따라 시간이 지나면서 발전합니다.

많은 프로젝트에는 자체적인 코딩 스타일 지침이 있습니다. 충돌이 있는 경우에는 해당 프로젝트에 한해 그 프로젝트 고유의 지침이 우선합니다.

어리석은 일관성은 편협한 마음의 도깨비입니다

Guido의 핵심 통찰 중 하나는 코드는 작성되는 것보다 훨씬 더 자주 읽힌다는 것입니다. 여기에 제시된 지침은 코드의 가독성을 높이고 다양한 Python 코드 전반에 걸쳐 일관성을 유지하는 것을 목표로 합니다. PEP 20에서 말하듯이 “가독성은 중요합니다”.

스타일 가이드는 일관성에 관한 것입니다. 이 스타일 가이드와의 일관성은 중요합니다. 프로젝트 내에서의 일관성은 더 중요합니다. 하나의 모듈이나 함수 안에서의 일관성이 가장 중요합니다.

하지만 일관성을 지키지 않아야 할 때를 아십시오 – 때로는 스타일 가이드의 권장 사항이 적용되지 않는 경우도 있습니다. 확신이 서지 않을 때는 최선의 판단을 내리십시오. 다른 예제들을 살펴보고 무엇이 가장 좋아 보이는지 결정하십시오. 그리고 주저하지 말고 질문하십시오!

특히, 이 PEP를 따르기 위해서 하위 호환성을 깨뜨리지 마십시오!

특정 지침을 무시해도 좋은 다른 타당한 이유는 다음과 같습니다:

  1. 지침을 적용하면 이 PEP를 따르는 코드를 읽는 데 익숙한 사람에게조차 코드의 가독성이 떨어지는 경우입니다.
  2. 마찬가지로 지침을 따르지 않는 주변 코드와 일관성을 유지하기 위한 경우입니다(아마도 역사적인 이유로) – 물론 이는 (진정한 XP 방식으로) 다른 사람이 어질러 놓은 것을 정리할 기회이기도 합니다.
  3. 해당 코드가 지침이 도입되기 전에 작성되었고, 그 코드를 수정할 다른 이유가 없는 경우입니다.
  4. 스타일 가이드가 권장하는 기능을 지원하지 않는 이전 버전의 Python과 코드가 호환성을 유지해야 하는 경우입니다.

코드 레이아웃

들여쓰기

들여쓰기 수준마다 공백 4칸을 사용하십시오.

연속 줄은 괄호, 대괄호, 중괄호 안에서 Python의 암시적 줄 결합을 사용하여 줄바꿈된 요소를 수직으로 정렬하거나, 내어쓰기 [1]를 사용하여 정렬해야 합니다. 내어쓰기를 사용할 때는 다음 사항을 고려해야 합니다. 첫 줄에는 인자가 없어야 하며, 연속 줄임이 명확히 구분되도록 추가 들여쓰기를 사용해야 합니다:

# 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)
# Wrong:

# Arguments on first line forbidden when not using vertical alignment.
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable.
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

연속 줄에서는 4칸 규칙이 선택 사항입니다.

선택 사항:

# Hanging indents *may* be indented to other than 4 spaces.
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)

if 문의 조건 부분이 길어서 여러 줄에 걸쳐 작성해야 하는 경우, 두 글자 키워드(즉, if)와 공백 하나, 그리고 여는 괄호를 합치면 여러 줄 조건식의 이어지는 줄에 자연스럽게 4칸 들여쓰기가 만들어진다는 점에 유의할 필요가 있습니다. 이는 if 문 안에 중첩되어 들여쓰기된 코드 블록과 시각적으로 충돌할 수 있는데, 이 코드 블록 역시 자연스럽게 4칸으로 들여쓰기되기 때문입니다. 이 PEP는 이러한 조건식 줄을 if 문 안에 중첩된 코드 블록과 시각적으로 어떻게 더 구분할지(또는 구분할지 여부)에 대해 명시적인 입장을 취하지 않습니다. 이 상황에서 허용되는 선택지에는 다음이 포함되지만, 이에 국한되지는 않습니다:

# 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()

(이항 연산자 앞에서 줄을 바꿀지 뒤에서 바꿀지에 대한 아래 논의도 참고하십시오.)

여러 줄 구문의 닫는 중괄호/대괄호/소괄호는 다음과 같이 리스트 마지막 줄의 공백이 아닌 첫 번째 문자 아래에 맞출 수도 있고:

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',
)

탭인가 공백인가?

공백이 선호되는 들여쓰기 방법입니다.

탭은 이미 탭으로 들여쓰기된 코드와 일관성을 유지하기 위해서만 사용해야 합니다.

Python에서는 들여쓰기에 탭과 공백을 섞어 쓸 수 없습니다.

최대 줄 길이

모든 줄은 최대 79자로 제한하십시오.

구조적 제약이 적은 긴 텍스트 블록(독스트링이나 주석)의 경우, 줄 길이를 72자로 제한해야 합니다.

필요한 편집기 창 너비를 제한하면 여러 파일을 나란히 열어 둘 수 있으며, 두 버전을 인접한 열에 보여 주는 코드 리뷰 도구를 사용할 때도 잘 맞습니다.

대부분의 도구에서 기본으로 적용되는 줄 바꿈은 코드의 시각적 구조를 흐트러뜨려 코드를 이해하기 더 어렵게 만듭니다. 이 제한은 도구가 줄을 바꿀 때 마지막 열에 표시 글리프를 넣더라도, 창 너비가 80으로 설정된 편집기에서 줄 바꿈이 일어나지 않도록 정한 것입니다. 일부 웹 기반 도구는 동적 줄 바꿈을 아예 제공하지 않을 수도 있습니다.

일부 팀은 더 긴 줄 길이를 강하게 선호합니다. 이 문제에 대해 합의할 수 있는 팀이 전적으로 또는 주로 유지 관리하는 코드라면, 주석과 독스트링은 여전히 72자에서 줄을 바꾼다는 조건으로 줄 길이 제한을 99자까지 늘려도 괜찮습니다.

Python 표준 라이브러리는 보수적이어서 줄 길이를 79자로 (독스트링과 주석은 72자로) 제한해야 합니다.

긴 줄을 나누는 데 선호되는 방법은 괄호, 대괄호, 중괄호 안에서 Python의 암시적 줄 연속을 사용하는 것입니다. 긴 줄은 표현식을 괄호로 감싸서 여러 줄로 나눌 수 있습니다. 줄을 이을 때는 백슬래시를 사용하기보다 이 방법을 우선적으로 사용해야 합니다.

그래도 때로는 백슬래시가 적절할 수 있습니다. 예를 들어 Python 3.10 이전에는 길게 여러 개로 이어지는 with 문에서 암시적 줄 연속을 사용할 수 없었으므로, 이 경우에는 백슬래시를 사용해도 괜찮았습니다:

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())

(이러한 여러 줄 with 문의 들여쓰기에 대한 추가적인 생각은 앞서 다룬 multiline if-statements에 대한 논의를 참고하십시오.)

또 다른 경우로 assert 문이 있습니다.

이어지는 줄은 반드시 적절하게 들여쓰기하십시오.

이항 연산자 앞에서 줄을 바꿔야 합니까, 뒤에서 바꿔야 합니까?

수십 년 동안 권장된 스타일은 이항 연산자 뒤에서 줄을 바꾸는 것이었습니다. 하지만 이 방식은 두 가지 면에서 가독성을 해칠 수 있습니다. 연산자들이 화면의 여러 열에 흩어지기 쉽고, 각 연산자가 피연산자에서 떨어져 이전 줄로 옮겨지게 됩니다. 다음 예에서는 어떤 항목이 더해지고 어떤 항목이 빼지는지 알아보려면 눈이 추가로 수고해야 합니다:

# Wrong:
# operators sit far away from their operands
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

이 가독성 문제를 해결하기 위해 수학자들과 그 출판사들은 반대의 관례를 따릅니다. 도널드 커누스(Donald Knuth)는 자신의 Computers and Typesetting 시리즈에서 이 전통적인 규칙을 다음과 같이 설명합니다: “문단 안의 수식은 항상 이항 연산과 관계 뒤에서 줄을 바꾸지만, 별도로 표시되는 수식은 항상 이항 연산 앞에서 줄을 바꿉니다” [3].

수학의 전통을 따르면 대개 더 읽기 쉬운 코드가 됩니다:

# Correct:
# easy to match operators with operands
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

Python 코드에서는 지역적으로 규칙이 일관되기만 하면 이항 연산자 앞이나 뒤에서 줄을 나누어도 됩니다. 새 코드에는 커누스의 스타일을 권장합니다.

빈 줄

최상위 함수 정의와 클래스 정의는 앞뒤를 빈 줄 두 개로 감싸십시오.

클래스 안의 메서드 정의는 앞뒤를 빈 줄 하나로 감쌉니다.

관련된 함수들의 그룹을 구분하기 위해 빈 줄을 추가로 (절제하여) 사용할 수 있습니다. 서로 관련된 한 줄짜리 코드 여러 개(예: 더미 구현 모음) 사이에서는 빈 줄을 생략할 수 있습니다.

함수 안에서는 논리적인 구획을 나타내기 위해 빈 줄을 절제하여 사용하십시오.

Python은 control-L(즉, ^L) 폼 피드 문자를 공백으로 받아들입니다. 많은 도구가 이 문자를 페이지 구분자로 취급하므로, 파일에서 관련된 부분을 페이지 단위로 구분하는 데 사용할 수 있습니다. 다만 일부 편집기와 웹 기반 코드 뷰어는 control-L을 폼 피드로 인식하지 못하고 그 자리에 다른 글리프를 표시할 수 있다는 점에 유의하십시오.

소스 파일 인코딩

코어 Python 배포판의 코드는 항상 UTF-8을 사용해야 하며, 인코딩 선언을 두어서는 안 됩니다.

표준 라이브러리에서 UTF-8이 아닌 인코딩은 테스트 목적으로만 사용해야 합니다. ASCII가 아닌 문자는 절제하여 사용하고, 가급적 장소와 사람 이름을 나타낼 때만 사용하십시오. ASCII가 아닌 문자를 데이터로 사용할 때에는 z̯̯͡a̧͎̺l̡͓̫g̹̲o̡̼̘ 같은 지저분한 유니코드 문자와 바이트 순서 표시(BOM)를 피하십시오.

Python 표준 라이브러리의 모든 식별자는 반드시 ASCII 문자로만 된 식별자를 사용해야 하며, 가능한 한 영어 단어를 사용해야 합니다(영어가 아닌 약어와 기술 용어를 사용하는 경우도 많습니다).

전 세계 사용자를 대상으로 하는 오픈 소스 프로젝트도 비슷한 정책을 채택할 것을 권장합니다.

임포트

  • 임포트는 보통 별도의 줄에 작성해야 합니다:
    # Correct:
    import os
    import sys
    
    # Wrong:
    import sys, os
    

    하지만 다음과 같이 작성하는 것은 괜찮습니다:

    # Correct:
    from subprocess import Popen, PIPE
    
  • 임포트는 항상 파일의 맨 위, 모듈 주석과 독스트링 바로 다음, 그리고 모듈 전역 변수와 상수 앞에 둡니다.

    임포트는 다음 순서로 묶어야 합니다:

    1. 표준 라이브러리 임포트.
    2. 관련된 서드파티 임포트.
    3. 로컬 애플리케이션/라이브러리 전용 임포트.

    각 임포트 그룹 사이에는 빈 줄을 하나 넣어야 합니다.

  • 절대 임포트를 권장합니다. 대개 더 읽기 쉽고, 임포트 시스템이 잘못 구성된 경우(예: 패키지 안의 디렉터리가 sys.path에 들어간 경우)에도 더 올바르게 동작하는(또는 적어도 더 나은 오류 메시지를 내는) 경향이 있기 때문입니다:
    import mypkg.sibling
    from mypkg import sibling
    from mypkg.sibling import example
    

    그러나 명시적 상대 임포트도 절대 임포트의 대안으로 허용됩니다. 특히 절대 임포트를 사용하면 불필요하게 장황해지는 복잡한 패키지 구조를 다룰 때 그렇습니다:

    from . import sibling
    from .sibling import example
    

    표준 라이브러리 코드는 복잡한 패키지 구조를 피하고 항상 절대 임포트를 사용해야 합니다.

  • 클래스를 담고 있는 모듈에서 클래스를 임포트할 때는 보통 다음과 같이 써도 괜찮습니다:
    from myclass import MyClass
    from foo.bar.yourclass import YourClass
    

    이렇게 쓸 때 지역 이름 충돌이 생긴다면 명시적으로 쓰십시오:

    import myclass
    import foo.bar.yourclass
    

    그리고 myclass.MyClass와 foo.bar.yourclass.YourClass를 사용하십시오.

  • 와일드카드 임포트(from <module> import *)는 피해야 합니다. 네임스페이스에 어떤 이름이 있는지 불분명하게 만들어 읽는 사람과 여러 자동화 도구를 모두 혼란스럽게 하기 때문입니다. 와일드카드 임포트를 정당화할 수 있는 사용 사례가 하나 있는데, 내부 인터페이스를 공개 API의 일부로 다시 공개하는 경우입니다(예를 들어, 인터페이스의 순수 Python 구현을 선택적 가속 모듈의 정의로 덮어쓰는데 정확히 어떤 정의가 덮어쓰일지 미리 알 수 없는 경우).

    이런 방식으로 이름을 다시 공개할 때도 공개 인터페이스와 내부 인터페이스에 관한 아래 지침은 여전히 적용됩니다.

모듈 수준 던더 이름

__all__, __author__, __version__ 등과 같은 모듈 수준 “던더”(즉, 앞뒤에 밑줄이 두 개씩 붙은 이름)는 모듈 독스트링 뒤에, 그리고 from __future__ 임포트를 제외한 모든 import 문 앞에 두어야 합니다. Python은 future 임포트가 모듈에서 독스트링을 제외한 다른 모든 코드보다 앞에 나와야 한다고 규정합니다:

"""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

문자열 따옴표

Python에서 작은따옴표 문자열과 큰따옴표 문자열은 같습니다. 이 PEP는 이에 대해 권장 사항을 제시하지 않습니다. 규칙을 하나 정하고 그것을 꾸준히 지키십시오. 다만 문자열에 작은따옴표나 큰따옴표 문자가 들어 있다면, 문자열 안에서 백슬래시를 쓰지 않도록 다른 쪽 따옴표를 사용하십시오. 그렇게 하면 가독성이 좋아집니다.

삼중 따옴표 문자열에는 PEP 257의 독스트링 규칙과 일관되도록 항상 큰따옴표 문자를 사용하십시오.

표현식과 문장의 공백

눈에 거슬리는 것들

다음과 같은 상황에서는 불필요한 공백을 피하십시오:

  • 소괄호, 대괄호, 중괄호 바로 안쪽:
    # 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 : : step]
    ham[ : upper]
    
  • 함수 호출의 인자 목록을 시작하는 여는 괄호 바로 앞:
    # Correct:
    spam(1)
    
    # Wrong:
    spam (1)
    
  • 인덱싱이나 슬라이싱을 시작하는 여는 괄호 바로 앞:
    # 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
    

기타 권장 사항

  • 어디에서도 후행 공백을 두지 마십시오. 후행 공백은 대개 눈에 보이지 않아서 혼란을 줄 수 있습니다. 예를 들어 백슬래시 뒤에 공백과 줄바꿈이 오면 줄 연속 표시로 인식되지 않습니다. 일부 편집기는 이를 보존하지 않으며, (CPython 자체처럼) 많은 프로젝트에는 이를 거부하는 pre-commit 훅, 즉 커밋 전 훅이 있습니다.
  • 다음 이항 연산자의 양쪽에는 항상 공백을 하나씩 두십시오: 대입(=), 복합 대입(+=, -= 등), 비교(==, <, >, !=, <=, >=, in, not in, is, is not), 불리언(and, or, not).
  • 우선순위가 서로 다른 연산자를 함께 사용한다면, 우선순위가 가장 낮은 연산자 주위에 공백을 넣는 것을 고려하십시오. 각자 판단하되, 공백을 두 개 이상 사용하지 말고 이항 연산자의 양쪽에는 항상 같은 양의 공백을 두십시오:
    # 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를 참고하십시오.):
    # Correct:
    def munge(input: AnyStr): ...
    def munge() -> PosInt: ...
    
    # Wrong:
    def munge(input:AnyStr): ...
    def munge()->PosInt: ...
    
  • = 기호가 키워드 인자를 나타내거나 어노테이션이 없는 함수 매개변수의 기본값을 나타낼 때는 그 주위에 공백을 두지 마십시오:
    # 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)
    

    하지만 인자 어노테이션과 기본값을 함께 쓸 때는 = 기호 주위에 공백을 두십시오:

    # 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): ...
    
  • 복합문(한 줄에 여러 문장을 쓰는 것)은 일반적으로 권장하지 않습니다:
    # 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:
    if foo == 'blah': do_blah_thing()
    for x in lst: total += x
    while t < 10: t = delay()
    

    절대 금지:

    # Wrong:
    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()
    

후행 쉼표를 사용하는 경우

후행 쉼표는 대개 선택 사항이지만, 요소가 하나인 튜플을 만들 때는 반드시 붙여야 합니다. 명확성을 위해 후자는 (기술적으로는 불필요한) 괄호로 감싸는 것을 권장합니다:

# Correct:
FILES = ('setup.cfg',)
# Wrong:
FILES = 'setup.cfg',

후행 쉼표가 불필요한 경우라도, 버전 관리 시스템을 사용하고 값, 인자, 임포트하는 항목의 목록이 시간이 지나면서 늘어날 것으로 예상될 때는 유용할 때가 많습니다. 이때의 패턴은 각 값(등)을 한 줄에 하나씩 두고 항상 후행 쉼표를 붙이며, 닫는 괄호/대괄호/중괄호는 다음 줄에 두는 것입니다. 그러나 (위에서 설명한 요소가 하나인 튜플의 경우를 제외하면) 닫는 구분자와 같은 줄에 후행 쉼표를 두는 것은 의미가 없습니다:

# Correct:
FILES = [
    'setup.cfg',
    'tox.ini',
    ]
initialize(FILES,
           error=True,
           )
# Wrong:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)

주석

코드와 모순되는 주석은 주석이 없는 것보다 나쁩니다. 코드가 바뀌면 항상 주석을 최신 상태로 유지하는 일을 최우선으로 삼으십시오!

주석은 완전한 문장이어야 합니다. 첫 단어는 대문자로 시작해야 하지만, 소문자로 시작하는 식별자라면 예외입니다(식별자의 대소문자는 절대 바꾸지 마십시오!).

블록 주석은 일반적으로 완전한 문장으로 이루어진 하나 이상의 단락으로 구성되며, 각 문장은 마침표로 끝납니다.

여러 문장으로 된 주석에서는 문장을 끝맺는 마침표 뒤에 공백을 한두 개 두어야 하지만, 마지막 문장 뒤에는 두지 않습니다.

주석을 작성하는 언어를 사용하는 다른 사람들이 주석을 명확하고 쉽게 이해할 수 있도록 하십시오.

영어권이 아닌 나라의 Python 개발자 여러분, 여러분의 언어를 모르는 사람이 코드를 절대 읽지 않으리라고 120% 확신하는 경우가 아니라면 주석을 영어로 작성하십시오.

블록 주석

블록 주석은 일반적으로 그 뒤에 오는 코드의 일부(또는 전체)에 적용되며, 해당 코드와 같은 수준으로 들여씁니다. 블록 주석의 각 줄은 # 하나와 공백 하나로 시작합니다(주석 안에서 들여쓴 텍스트인 경우는 예외입니다).

블록 주석 안의 문단은 # 하나만 있는 줄로 구분합니다.

인라인 주석

인라인 주석은 아껴서 사용하십시오.

인라인 주석은 문(statement)과 같은 줄에 있는 주석입니다. 인라인 주석은 문과 최소 두 칸의 공백으로 떨어져 있어야 합니다. 인라인 주석은 # 하나와 공백 하나로 시작해야 합니다.

뻔한 내용을 말하는 인라인 주석은 불필요하며, 실제로는 오히려 주의를 산만하게 합니다. 이렇게 하지 마십시오:

x = x + 1                 # Increment x

하지만 때로는 이런 주석이 유용합니다:

x = x + 1                 # Compensate for border

문서화 문자열

좋은 문서화 문자열(일명 “독스트링”)을 작성하는 규칙은 PEP 257에 영구히 기록되어 있습니다.

  • 모든 공개 모듈, 함수, 클래스, 메서드에 독스트링을 작성하십시오. 비공개 메서드에는 독스트링이 필요하지 않지만, 메서드가 무엇을 하는지 설명하는 주석은 있어야 합니다. 이 주석은 def 줄 다음에 와야 합니다.
  • PEP 257은 좋은 독스트링 규칙을 설명합니다. 무엇보다 중요한 점으로, 여러 줄 독스트링을 끝내는 """는 단독으로 한 줄을 차지해야 한다는 점에 유의하십시오:
    """Return a foobang
    
    Optional plotz says to frobnicate the bizbaz first.
    """
    
  • 한 줄짜리 독스트링에서는 닫는 """를 같은 줄에 두십시오:
    """Return an ex-parrot."""
    

명명 규칙

Python 라이브러리의 명명 규칙은 다소 뒤죽박죽이어서 완전히 일관되게 만들 수는 없을 것입니다. 그렇지만 현재 권장되는 명명 기준은 다음과 같습니다. 새 모듈과 패키지는 (서드파티 프레임워크를 포함하여) 이 기준에 따라 작성해야 합니다. 다만 기존 라이브러리가 다른 스타일을 따르고 있다면 내부 일관성을 우선합니다.

최우선 원칙

API의 공개 부분으로서 사용자에게 보이는 이름은 구현보다는 사용 방식을 반영하는 규칙을 따라야 합니다.

서술: 명명 스타일

명명 스타일에는 여러 가지가 있습니다. 이름이 무엇에 쓰이는지와 관계없이 어떤 명명 스타일이 사용되고 있는지 알아볼 수 있으면 도움이 됩니다.

흔히 구분되는 명명 스타일은 다음과 같습니다:

  • b (소문자 한 글자)
  • B (대문자 한 글자)
  • lowercase
  • lower_case_with_underscores
  • UPPERCASE
  • UPPER_CASE_WITH_UNDERSCORES
  • CapitalizedWords (CapWords 또는 CamelCase라고도 하며, 글자 모양이 울퉁불퉁해 보여서 이런 이름이 붙었습니다 [4]). StudlyCaps라고 부르기도 합니다.

    참고: CapWords에서 약어를 사용할 때는 약어의 모든 글자를 대문자로 쓰십시오. 따라서 HttpServerError보다 HTTPServerError가 더 좋습니다.

  • mixedCase (첫 글자가 소문자라는 점이 CapitalizedWords와 다릅니다!)
  • Capitalized_Words_With_Underscores (보기 흉합니다!)

관련된 이름들을 짧고 고유한 접두사로 묶는 스타일도 있습니다. 이 방식은 Python에서는 잘 쓰이지 않지만, 빠짐없이 다루기 위해 언급합니다. 예를 들어 os.stat() 함수가 반환하는 튜플의 항목들에는 전통적으로 st_mode, st_size, st_mtime 등과 같은 이름이 붙습니다. (POSIX 시스템 호출 구조체의 필드와 대응된다는 점을 강조하려고 이렇게 하며, 이는 그 구조체에 익숙한 프로그래머에게 도움이 됩니다.)

X11 라이브러리는 모든 공개 함수 이름 앞에 X를 붙입니다. Python에서는 속성 이름과 메서드 이름 앞에 객체가 붙고 함수 이름 앞에 모듈 이름이 붙으므로, 일반적으로 이 스타일은 불필요한 것으로 여겨집니다.

또한 앞이나 뒤에 밑줄을 붙이는 다음과 같은 특수한 형태가 인정됩니다(이들은 일반적으로 어떤 대소문자 규칙과도 함께 쓸 수 있습니다):

  • _single_leading_underscore: 약한 “내부용” 표시입니다. 예를 들어 from M import *는 이름이 밑줄로 시작하는 객체를 임포트하지 않습니다.
  • single_trailing_underscore_: Python 키워드와의 충돌을 피하기 위해 관례적으로 사용합니다. 예를 들면 다음과 같습니다:
    tkinter.Toplevel(master, class_='ClassName')
    
  • __double_leading_underscore: 클래스 속성의 이름에 사용하면 이름 맹글링(name mangling)이 일어납니다(클래스 FooBar 안에서 __boo는 _FooBar__boo가 됩니다. 아래를 참고하십시오).
  • __double_leading_and_trailing_underscore__: 사용자가 제어하는 네임스페이스에 있는 “매직” 객체나 속성입니다. 예: __init__, __import__, __file__. 이런 이름을 절대 새로 만들지 마십시오. 문서에 설명된 대로만 사용하십시오.

규범: 명명 규칙

피해야 할 이름

‘l’(소문자 엘), ‘O’(대문자 오), ‘I’(대문자 아이)를 한 글자짜리 변수 이름으로 절대 사용하지 마십시오.

일부 글꼴에서는 이 문자들을 숫자 1이나 0과 구별할 수 없습니다. ‘l’을 쓰고 싶을 때는 대신 ‘L’을 사용하십시오.

ASCII 호환성

표준 라이브러리에서 사용하는 식별자는 PEP 3131의 정책 섹션에 설명된 대로 ASCII와 호환되어야 합니다.

패키지와 모듈 이름

모듈 이름은 모두 소문자로 된 짧은 이름이어야 합니다. 가독성이 좋아진다면 모듈 이름에 밑줄을 사용해도 됩니다. Python 패키지도 짧고 모두 소문자로 된 이름을 가져야 하지만, 밑줄 사용은 권장하지 않습니다.

C나 C++로 작성된 확장 모듈에 더 고수준의(예: 더 객체 지향적인) 인터페이스를 제공하는 Python 모듈이 함께 있는 경우, C/C++ 모듈의 이름은 밑줄로 시작합니다(예: _socket).

클래스 이름

클래스 이름에는 일반적으로 CapWords 관례를 사용해야 합니다.

인터페이스가 문서화되어 있고 주로 호출 가능 객체로 사용되는 경우에는 함수 명명 관례를 대신 사용할 수 있습니다.

내장 이름에는 별도의 관례가 있다는 점에 유의하십시오. 대부분의 내장 이름은 한 단어(또는 두 단어를 붙여 쓴 것)이며, CapWords 관례는 예외 이름과 내장 상수에만 사용됩니다.

타입 변수 이름

PEP 484에서 도입된 타입 변수의 이름은 일반적으로 CapWords를 사용하되 T, AnyStr, Num처럼 짧은 이름을 선호해야 합니다. 공변 또는 반공변 동작을 선언하는 데 사용되는 변수에는 각각 _co 또는 _contra 접미사를 붙이는 것을 권장합니다:

from typing import TypeVar

VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)

예외 이름

예외는 클래스여야 하므로 여기에도 클래스 명명 관례가 적용됩니다. 다만 (예외가 실제로 오류인 경우) 예외 이름에 “Error” 접미사를 붙여야 합니다.

전역 변수 이름

(이러한 변수는 한 모듈 안에서만 사용하려는 것이기를 바랍시다.) 관례는 함수의 관례와 거의 같습니다.

from M import *를 통해 사용하도록 설계된 모듈은 전역 변수가 내보내지지 않도록 __all__ 메커니즘을 사용하거나, 그러한 전역 변수 앞에 밑줄을 붙이는 예전 관례를 사용해야 합니다(이 전역 변수가 “모듈 비공개”임을 나타내고 싶을 때 이렇게 할 수 있습니다).

함수와 변수 이름

함수 이름은 소문자로 쓰고, 가독성을 높이는 데 필요하다면 단어를 밑줄로 구분해야 합니다.

변수 이름도 함수 이름과 같은 관례를 따릅니다.

mixedCase는 하위 호환성을 유지하기 위해 이미 그 스타일이 주로 쓰이는 맥락(예: threading.py)에서만 허용됩니다.

함수와 메서드 인자

인스턴스 메서드의 첫 번째 인자로는 항상 self를 사용하십시오.

클래스 메서드의 첫 번째 인자로는 항상 cls를 사용하십시오.

함수 인자의 이름이 예약된 키워드와 충돌하는 경우, 일반적으로 약어를 쓰거나 철자를 바꾸기보다는 끝에 밑줄 하나를 붙이는 것이 좋습니다. 따라서 class_가 clss보다 낫습니다. (아마도 동의어를 사용해 그러한 충돌을 피하는 편이 더 나을 것입니다.)

메서드 이름과 인스턴스 변수

함수 명명 규칙을 사용하십시오. 소문자로 쓰고, 가독성을 높이는 데 필요하다면 단어를 밑줄로 구분합니다.

밑줄 하나로 시작하는 이름은 비공개 메서드와 인스턴스 변수에만 사용하십시오.

서브클래스와의 이름 충돌을 피하려면 밑줄 두 개로 시작하는 이름을 사용하여 Python의 이름 맹글링 규칙이 적용되게 하십시오.

Python은 이러한 이름을 클래스 이름으로 맹글링합니다. 클래스 Foo에 __a라는 이름의 속성이 있으면 Foo.__a로는 접근할 수 없습니다. (그래도 고집스러운 사용자라면 Foo._Foo__a를 호출하여 접근할 수 있습니다.) 일반적으로 밑줄 두 개로 시작하는 이름은 서브클래싱을 염두에 두고 설계된 클래스에서 속성 이름 충돌을 피하기 위해서만 사용해야 합니다.

참고: __names의 사용에 대해서는 다소 논란이 있습니다(아래 참조).

상수

상수는 보통 모듈 수준에서 정의하며, 모두 대문자로 쓰고 단어는 밑줄로 구분합니다. MAX_OVERFLOW와 TOTAL이 그 예입니다.

상속을 고려한 설계

클래스의 메서드와 인스턴스 변수(통틀어 “속성”)를 공개로 할지 비공개로 할지 항상 결정하십시오. 확신이 서지 않으면 비공개를 선택하십시오. 공개 속성을 비공개로 바꾸는 것보다 나중에 공개로 바꾸는 것이 더 쉽습니다.

공개 속성은 여러분의 클래스와 관계없는 클라이언트가 사용하리라 예상하는 속성이며, 여러분은 하위 호환성을 깨뜨리는 변경을 피하겠다고 약속하는 것입니다. 비공개 속성은 서드파티가 사용하도록 의도되지 않은 속성입니다. 비공개 속성은 변경되거나 아예 제거되지 않는다고 보장하지 않습니다.

Python에서는 (일반적으로 불필요할 만큼 많은 작업을 하지 않는 한) 진정으로 private인 속성이 없으므로, 여기서는 “private”이라는 용어를 사용하지 않습니다.

또 다른 범주의 속성은 “서브클래스 API”(다른 언어에서는 흔히 “protected”라고 부릅니다)에 속하는 속성입니다. 어떤 클래스는 상속을 통해 클래스 동작의 일부를 확장하거나 수정하도록 설계됩니다. 그러한 클래스를 설계할 때는 어떤 속성이 공개인지, 어떤 속성이 서브클래스 API에 속하는지, 어떤 속성이 진정으로 베이스 클래스에서만 사용되어야 하는지 명시적으로 결정하도록 주의하십시오.

이 점을 염두에 둔 파이썬다운 지침은 다음과 같습니다:

  • 공개 속성은 밑줄로 시작하지 않아야 합니다.
  • 공개 속성 이름이 예약된 키워드와 충돌한다면, 속성 이름 끝에 밑줄 하나를 붙이십시오. 이 방법이 약어나 변형된 철자보다 바람직합니다. (그러나 이 규칙에도 불구하고, 클래스임이 알려진 변수나 인자, 특히 클래스 메서드의 첫 번째 인자에는 ‘cls’라는 철자가 선호됩니다.)

    참고 1: 클래스 메서드에 관해서는 위의 인자 이름 권고 사항을 참조하십시오.

  • 단순한 공개 데이터 속성의 경우, 복잡한 접근자/변경자 메서드 없이 속성 이름만 노출하는 것이 가장 좋습니다. 단순한 데이터 속성에 기능적인 동작을 추가해야 할 때가 오더라도 Python은 이를 쉽게 확장할 수 있는 방법을 제공한다는 점을 기억하십시오. 그런 경우에는 프로퍼티를 사용하여 단순한 데이터 속성 접근 문법 뒤에 기능적 구현을 숨기십시오.

    참고 1: 기능적 동작에는 가급적 부작용이 없도록 하십시오. 다만 캐싱과 같은 부작용은 일반적으로 괜찮습니다.

    참고 2: 계산 비용이 큰 연산에는 프로퍼티를 사용하지 마십시오. 속성 표기법은 호출자가 접근 비용이 (상대적으로) 적다고 믿게 만듭니다.

  • 클래스가 서브클래싱되도록 의도되었고 서브클래스가 사용하지 않기를 바라는 속성이 있다면, 그 속성 이름을 밑줄 두 개로 시작하고 끝에는 밑줄을 붙이지 않는 것을 고려하십시오. 이렇게 하면 클래스 이름을 속성 이름에 맹글링해 넣는 Python의 이름 맹글링 알고리즘이 적용됩니다. 이는 서브클래스에 실수로 같은 이름의 속성이 포함되더라도 속성 이름 충돌을 피하는 데 도움이 됩니다.

    참고 1: 맹글링된 이름에는 단순한 클래스 이름만 사용된다는 점에 유의하십시오. 따라서 서브클래스가 같은 클래스 이름과 같은 속성 이름을 모두 선택하면 여전히 이름 충돌이 발생할 수 있습니다.

    참고 2: 이름 맹글링은 디버깅이나 __getattr__() 같은 특정 용도를 덜 편리하게 만들 수 있습니다. 그러나 이름 맹글링 알고리즘은 잘 문서화되어 있으며 수동으로 수행하기도 쉽습니다.

    참고 3: 모든 사람이 이름 맹글링을 좋아하는 것은 아닙니다. 우발적인 이름 충돌을 피해야 할 필요성과 고급 호출자가 사용할 가능성 사이에서 균형을 맞추도록 노력하십시오.

공개 인터페이스와 내부 인터페이스

모든 하위 호환성 보장은 공개 인터페이스에만 적용됩니다. 따라서 사용자가 공개 인터페이스와 내부 인터페이스를 명확하게 구별할 수 있는 것이 중요합니다.

문서화된 인터페이스는 공개로 간주합니다. 다만 문서에서 잠정적인 인터페이스이거나 통상적인 하위 호환성 보장에서 제외되는 내부 인터페이스라고 명시적으로 선언한 경우는 예외입니다. 문서화되지 않은 모든 인터페이스는 내부 인터페이스로 간주해야 합니다.

인트로스펙션을 더 잘 지원하려면 모듈은 __all__ 속성을 사용하여 공개 API에 속한 이름을 명시적으로 선언해야 합니다. __all__을 빈 리스트로 설정하면 해당 모듈에 공개 API가 없다는 뜻입니다.

__all__을 적절히 설정했더라도 내부 인터페이스(패키지, 모듈, 클래스, 함수, 속성 또는 기타 이름)에는 여전히 앞에 밑줄 하나를 붙여야 합니다.

인터페이스를 포함하는 네임스페이스(패키지, 모듈 또는 클래스) 중 하나라도 내부로 간주되면 그 인터페이스도 내부로 간주됩니다.

임포트된 이름은 항상 구현 세부 사항으로 간주해야 합니다. 다른 모듈은 이렇게 임포트된 이름에 간접적으로 접근하는 방식에 의존해서는 안 됩니다. 단, os.path나 하위 모듈의 기능을 노출하는 패키지의 __init__ 모듈처럼 그 이름이 포함하는 모듈의 API 일부로 명시적으로 문서화된 경우는 예외입니다.

프로그래밍 권장 사항

  • 코드는 Python의 다른 구현(PyPy, Jython, IronPython, Cython, Psyco 등)에 불리하지 않은 방식으로 작성해야 합니다.

    예를 들어 a += b나 a = a + b 형태의 문장에서 CPython이 제자리(in-place) 문자열 연결을 효율적으로 구현한다는 점에 의존하지 마십시오. 이 최적화는 CPython에서조차 불안정하며(일부 타입에서만 동작합니다), 참조 카운팅을 사용하지 않는 구현에는 아예 존재하지 않습니다. 라이브러리에서 성능이 중요한 부분에는 대신 ''.join() 형태를 사용해야 합니다. 이렇게 하면 여러 구현에서 문자열 연결이 선형 시간에 이루어지도록 보장할 수 있습니다.

  • None과 같은 싱글턴과의 비교는 항상 is나 is not으로 해야 하며, 절대 동등 연산자를 사용해서는 안 됩니다.

    또한 실제로는 if x is not None을 의도하면서 if x라고 쓰지 않도록 주의하십시오. 예를 들어 기본값이 None인 변수나 인자가 다른 값으로 설정되었는지 검사할 때가 그렇습니다. 그 다른 값이 불리언 문맥에서 거짓이 될 수 있는 타입(컨테이너 등)일 수도 있기 때문입니다!

  • not ... is 대신 is not 연산자를 사용하십시오. 두 표현식은 기능적으로 동일하지만, 전자가 더 읽기 쉬우므로 선호됩니다:
    # Correct:
    if foo is not None:
    
    # Wrong:
    if not foo is None:
    
  • 풍부한 비교(rich comparison)로 순서 연산을 구현할 때는 다른 코드가 특정 비교만 사용하리라고 기대하기보다 여섯 가지 연산(__eq__, __ne__, __lt__, __le__, __gt__, __ge__)을 모두 구현하는 것이 가장 좋습니다.

    이 수고를 최소화할 수 있도록 functools.total_ordering() 데코레이터가 빠진 비교 메서드를 생성해 주는 도구를 제공합니다.

    PEP 207에 따르면 Python은 반사성 규칙을 실제로 전제로 합니다. 따라서 인터프리터는 y > x를 x < y로, y >= x를 x <= y로 바꿀 수 있으며, x == y와 x != y의 인자를 서로 바꿀 수도 있습니다. sort()와 min() 연산은 반드시 < 연산자를 사용하며, max() 함수는 > 연산자를 사용합니다. 그렇지만 다른 문맥에서 혼란이 생기지 않도록 여섯 가지 연산을 모두 구현하는 것이 가장 좋습니다.

  • 람다 표현식을 식별자에 직접 바인딩하는 대입문 대신 항상 def 문을 사용하십시오:
    # Correct:
    def f(x): return 2*x
    
    # Wrong:
    f = lambda x: 2*x
    

    첫 번째 형태를 사용하면 결과 함수 객체의 이름이 일반적인 ‘<lambda>’가 아니라 구체적으로 ‘f’가 됩니다. 이는 일반적으로 트레이스백과 문자열 표현에 더 유용합니다. 대입문을 사용하면 람다 표현식이 명시적인 def 문보다 나은 유일한 이점(즉, 더 큰 표현식 안에 포함될 수 있다는 점)이 사라집니다.

  • 예외는 BaseException이 아니라 Exception에서 파생하십시오. BaseException을 직접 상속하는 것은 잡는 것이 거의 항상 잘못인 예외에만 사용합니다.

    예외 계층 구조는 예외가 발생하는 위치가 아니라 예외를 잡는 코드가 필요로 할 만한 구분을 기준으로 설계하십시오. 단순히 “문제가 발생했습니다”라고 알리는 데 그치지 말고, “무엇이 잘못되었는가?”라는 질문에 프로그램적으로 답할 수 있도록 하십시오(내장 예외 계층 구조에서 이 교훈을 얻은 사례는 PEP 3151을 참고하십시오).

    여기에도 클래스 명명 규칙이 적용됩니다. 다만 예외가 오류라면 예외 클래스 이름에 “Error” 접미사를 붙여야 합니다. 비지역 흐름 제어나 그 밖의 신호 전달에 쓰이는, 오류가 아닌 예외에는 특별한 접미사를 붙일 필요가 없습니다.

  • 예외 연쇄를 적절히 사용하십시오. 원래 트레이스백을 잃지 않으면서 예외를 명시적으로 대체했음을 나타내려면 raise X from Y를 사용해야 합니다.

    (raise X from None을 사용하여) 내부 예외를 의도적으로 대체할 때는 관련 세부 정보를 새 예외로 옮기십시오(예를 들어 KeyError를 AttributeError로 변환할 때 속성 이름을 유지하거나, 원래 예외의 텍스트를 새 예외 메시지에 포함하십시오).

  • 예외를 잡을 때는 맨 except: 절 대신 가능한 한 구체적인 예외를 지정하십시오:
    try:
        import platform_specific_module
    except ImportError:
        platform_specific_module = None
    

    맨 except: 절은 SystemExit와 KeyboardInterrupt 예외까지 잡으므로 Control-C로 프로그램을 중단하기가 어려워지고, 다른 문제를 가릴 수도 있습니다. 프로그램 오류를 알리는 모든 예외를 잡으려면 except Exception:을 사용하십시오(맨 except는 except BaseException:과 같습니다).

    경험상 맨 ‘except’ 절은 다음 두 경우에만 사용하는 것이 좋습니다:

    1. 예외 핸들러가 트레이스백을 출력하거나 로깅하는 경우입니다. 이렇게 하면 최소한 사용자는 오류가 발생했다는 사실을 알 수 있습니다.
    2. 코드가 정리 작업을 한 뒤 raise로 예외를 위로 전파해야 하는 경우입니다. 이 경우에는 try...finally가 더 나은 방법일 수 있습니다.
  • 운영 체제 오류를 잡을 때는 errno 값의 인트로스펙션보다 Python 3.3에서 도입된 명시적 예외 계층을 사용하십시오.
  • 또한 모든 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 문을 사용해도 됩니다.
  • 컨텍스트 관리자가 자원의 획득과 해제 외에 다른 작업도 한다면 별도의 함수나 메서드를 통해 호출해야 합니다:
    # Correct:
    with conn.begin_transaction():
        do_stuff_in_transaction(conn)
    
    # Wrong:
    with conn:
        do_stuff_in_transaction(conn)
    

    뒤의 예제에는 __enter__와 __exit__ 메서드가 트랜잭션 후 연결을 닫는 것 외에 다른 작업을 한다는 사실을 알려 주는 정보가 전혀 없습니다. 이런 경우에는 명시적으로 작성하는 것이 중요합니다.

  • return 문을 일관되게 작성하십시오. 함수 안의 return 문은 모두 표현식을 반환하거나, 모두 반환하지 않아야 합니다. return 문 중 하나라도 표현식을 반환한다면, 값을 반환하지 않는 return 문은 모두 return None으로 명시해야 하며, (도달할 수 있다면) 함수 끝에도 명시적인 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)
    
  • 접두사나 접미사를 확인할 때는 문자열 슬라이싱 대신 ''.startswith()와 ''.endswith()를 사용하십시오.

    startswith()와 endswith()가 더 깔끔하고 실수할 여지도 적습니다:

    # Correct:
    if foo.startswith('bar'):
    
    # Wrong:
    if foo[:3] == 'bar':
    
  • 객체 타입을 비교할 때는 타입을 직접 비교하지 말고 항상 isinstance()를 사용해야 합니다:
    # Correct:
    if isinstance(obj, int):
    
    # Wrong:
    if type(obj) is type(1):
    
  • 시퀀스(문자열, 리스트, 튜플)는 빈 시퀀스가 거짓이라는 점을 활용하십시오:
    # Correct:
    if not seq:
    if seq:
    
    # Wrong:
    if len(seq):
    if not len(seq):
    
  • 끝에 붙은 공백에 의미가 있는 문자열 리터럴을 작성하지 마십시오. 이런 끝 공백은 눈으로 구별할 수 없으며, 일부 편집기(최근에는 reindent.py도)가 이를 잘라 냅니다.
  • 불리언 값을 ==로 True나 False와 비교하지 마십시오:
    # Correct:
    if greeting:
    
    # Wrong:
    if greeting == True:
    

    더 나쁜 예:

    # Wrong:
    if greeting is True:
    
  • try...finally의 finally 스위트 안에서 흐름 제어 문 return/break/continue가 finally 스위트 밖으로 제어를 옮기게 된다면, 이런 문은 사용하지 않는 것이 좋습니다. 이런 문은 finally 스위트를 통해 전파되고 있는 활성 예외를 암묵적으로 취소하기 때문입니다:
    # Wrong:
    def foo():
        try:
            1 / 0
        finally:
            return 42
    

함수 어노테이션

PEP 484가 채택됨에 따라 함수 어노테이션에 대한 스타일 규칙이 변경되었습니다.

  • 함수 어노테이션은 PEP 484 문법을 사용해야 합니다(어노테이션 서식에 관한 몇 가지 권고 사항은 앞 절에 있습니다).
  • 이전에 이 PEP에서 권장했던 어노테이션 스타일 실험은 더 이상 권장하지 않습니다.
  • 그러나 표준 라이브러리 밖에서는 이제 PEP 484의 규칙 안에서 실험하는 것을 권장합니다. 예를 들어 대규모 서드파티 라이브러리나 애플리케이션에 PEP 484 스타일의 타입 어노테이션을 달아 보고, 그 어노테이션을 추가하기가 얼마나 쉬웠는지 검토하고, 어노테이션이 있으면 코드를 이해하기가 더 쉬워지는지 관찰하는 것입니다.
  • Python 표준 라이브러리는 이러한 어노테이션을 도입하는 데 보수적이어야 하지만, 새 코드나 대규모 리팩터링에서는 사용할 수 있습니다.
  • 함수 어노테이션을 다른 용도로 사용하려는 코드에서는 다음과 같은 형식의 주석을 파일 상단 근처에 두는 것을 권장합니다:
    # type: ignore
    

    이 주석은 타입 검사기가 모든 어노테이션을 무시하도록 합니다. (타입 검사기의 경고를 더 세밀하게 끄는 방법은 PEP 484에서 찾을 수 있습니다.)

  • 린터와 마찬가지로 타입 검사기는 선택적으로 사용하는 별도의 도구입니다. Python 인터프리터는 기본적으로 타입 검사 때문에 어떠한 메시지도 출력해서는 안 되며, 어노테이션에 따라 동작을 바꿔서도 안 됩니다.
  • 타입 검사기를 사용하고 싶지 않은 사용자는 자유롭게 무시해도 됩니다. 그러나 서드파티 라이브러리 패키지의 사용자는 해당 패키지에 대해 타입 검사기를 실행하고 싶어 할 수 있습니다. 이를 위해 PEP 484는 스텁 파일 사용을 권장합니다. 스텁 파일은 타입 검사기가 대응하는 .py 파일보다 우선하여 읽는 .pyi 파일입니다. 스텁 파일은 라이브러리와 함께 배포하거나, (라이브러리 작성자의 허락을 받아) typeshed 저장소 [5]를 통해 별도로 배포할 수 있습니다.

변수 어노테이션

PEP 526은 변수 어노테이션을 도입했습니다. 변수 어노테이션에 대한 스타일 권고 사항은 위에서 설명한 함수 어노테이션의 권고 사항과 비슷합니다:

  • 모듈 수준 변수, 클래스 변수와 인스턴스 변수, 지역 변수에 대한 어노테이션은 콜론 뒤에 공백을 하나 두어야 합니다.
  • 콜론 앞에는 공백을 두지 않아야 합니다.
  • 대입에 우변이 있다면 동등 기호의 양쪽에 정확히 한 칸씩 공백을 두어야 합니다:
    # 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 버전에서 스텁 파일에 권장되는 문법입니다(자세한 내용은 PEP 484를 참조하십시오).

각주

참고 문헌