본문 바로가기
Python

PEP 8 - Pythonic하게 파이썬 코딩을 하는 방법

2023. 1. 24.

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를 준수하기 위해 이전 버전과의 호환성을 깨지 마라.

가이드라인을 무시해도 되는 몇 가지 좋은 이유
1. 가이드라인을 적용하면 코드가 더 읽기 어려워지는 경우. 심지어 이 PEP를 따르는 코드가 익숙한 사람에게도
2. 주변의 코드와 일관성을 유지해야하는 경우(아마 역사적인 이유)
3. 가이드라인이 도입되기 이전에 작성된 코드
4. 스타일 가이드에서 권장하는 기능을 지원하지 않는 이전 버전의 파이썬과의 호환성을 유지해야 할 경우

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


다음 연산자들은 항상 단일 공백으로 둘러싸야한다
1. 대입이나 복합대입연산자 (=, +=, -= 등)
2. 비교 연산자 (==, <, <=, >, >=, is, in 등)
3. 논리 연산자 (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/

 

PEP 8 – Style Guide for Python Code | peps.python.org

PEP 8 – Style Guide for Python Code Author: Guido van Rossum , Barry Warsaw , Nick Coghlan Status: Active Type: Process Created: 05-Jul-2001 Post-History: 05-Jul-2001, 01-Aug-2013 Table of Contents This document gives coding conventions for the Python co

peps.python.org



높은 수준의 Python 코드를 작성하기 위한 파이썬의 철학
PEP 20 : The Zen of Python 또한 읽어보길 강력히 추천한다.

반응형

댓글