python

PEP 8 - 파이썬 코드 스타일 가이드

kimjy 2021. 12. 6. 11:52

파이썬 코드를 작성하다 보면, 아래와 같이 함수 이름을 고민할 경우가 있다. 또 들여쓰기를 할 때 tab을 사용할 것인지, 혹은 스페이스를 4번 사용할 것인 지를 고민하는 경우가 있다. 이러한 경우를 위해 파이썬 공식 홈페이지에서는 PEP8이라는 파이썬 코드 스타일 가이드를 제공하고 있다. 본 포스트는 파이썬 코드 스타일 가이드를 정리하여, 추후 코드 작성에서 올바른 스타일로 코드를 작성하고자 한다.

 

#변수 명의 다양한 스타일
var_name
varName
VarName
varname

들여쓰기

  • 들여쓰기는 4개의 스페이스를 사용할 것
  • 첫번째 줄에 인자가 있으면 괄호에 맞추어 수직정렬을 할 것
  • 첫번째 줄에 인자가 없으면 추가로 들여쓰기를 하여 아랫줄과 구분할 것
[옳은 예]
#괄호에 맞춰서 정렬을 하는 경우
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)

#들여쓰기를 추가하여 함수 호출이 끝나지 않았다는 것을 알림
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는 두글자이므로 if와 ( 사이에 스페이스를 하나 두면 스페이스 4개와 비슷한 효과가 있을 것
  • if문에 대해서는 PEP가 큰 권고사항을 주고 있지는 않으므로, 아래와 같은 예제처럼 코드를 작성하면 될 것
# 추가적인 들여쓰기가 없음.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()
    
#if문 끝에 주석을 추가하여 아래 행과 구분이 가도록 할 것.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()
    
#들여쓰기를 추가하여 아래 행과 구분되도록 할 것.
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_argument(
    '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',
)

 

탭 vs 스페이스?

  • 스페이스를 사용하는 것이 권장됨
  • 다만 기존의 코드가 탭을 사용했다면 탭을 사용할 것
  • 단 탭과 스페이스를 섞어서 쓰지 말 것

 

한 줄에 최대로 사용할 수 있는 글자 수

  • 한줄에는 최돼 79글자만을 사용할 것이 권장됨
  • 79글자가 넘어가는 경우에는 "\"(백슬래쉬)를 사용하면 됨

줄 바뀜 시 연산자 위치

  • 줄이 너무 길어서 줄을 바꾸어야 할 때, 연산자를 바꾸기 전에 사용할 지 후에 사용할 지에 대해 고민이 필요하다.
  • 기존에는 줄을 바꾸기 전에 연산자를 기입하였지만, 파이썬에서는 가독성을 위하여 줄을 바꾼 후 연산자를 기입하는 것을 권장한다.
  • 아래는 줄 바뀜 시 연산자를 위치시키는 예제이다.
[옳은 예]
#연산자를 줄 바꾼 후에 사용
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

[틀린 예] 
#연산자를 줄 바꾸기 전에 사용
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

 

공백에 관한 것

  • 최고 단계의 함수나 클래스를 정의하면 2줄의 공백을 넣도록 한다.
  • 클래스 안의 메서드를 정의하면 1줄의 공백을 넣도록 한다.
  • 추가적인 공백은 함수들의 그룹을 구분할 때 유용하게 사용 될 수 있다.
class TestClass():


    def test_action(self, content):
        pass
        
    def test_program(self, content):
        pass
     
     
class ValidateClass():


    def validate_action(self, content):
        pass
        
    def validate_program(self, content):
        pass

 

파일 인코딩

  • 파이썬의 코드는 UTF-8방식을 따르도록 한다.

 

import

  • import문을 사용할 때에는 줄을 바꿔서 사용하도록 한다.
  • import문은 항상 코드의 위쪽에 위치하도록 한다.
  • import는 아래의 순서대로 그룹지어서 사용하도록 한다.
  1. Standard library imports
  2. Related third party imports
  3. Local application/library specific imports
    (각 그룹 사이에는 공백을 두는 것을 추천한다.)
[옳은 예]
import os
import sys

[틀린 예]
import sys,os

 

혹은 아래의 경우에는 괜찮다.

[옳은 예]
from subprocess import Popen, PIPE

 

  • ablsolute import를 하는 것을 추천한다. 이는 코드의 가독성을 높이고, 버그를 줄이기 때문이다.
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example

 

  • 다만 아래와 같이 relative import가 간결한 표현일 경우에는 허용한다.
from . import sibling
from .sibling import example

 

  • 모듈 안의 클래스를 import할 때에는 아래와 같이 사용할 수 있다.
from myclass import MyClass
from foo.bar.yourclass import YourClass

 

  • class 이름때문에 충돌이 발생할 경우 아래와 같이 import 하도록 한다
import myclass
import foo.bar.yourclass

 

  • 단 wildcard(*) import는 피하도록 한다.
  • 이는 가독성을 해치고, 더 나아가서 automated tools를 혼란스럽게 하기 때문이다.

Module Level Dunder Names

__all__, __author__, __version__과 같은 것들을 dunder Name이라고 부른다. 이 것들은 모듈 주석과 import 사이에 위치하여야 한다. 단, from __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

 

문자열 따옴표

  • 파이썬에서 문자열을 생성할 때에는 따옴표나 쌍따옴표를 사용하면 된다. 두 기호간의 구분은 없다.

 

공백에 관한 것

  • 괄호 안에 사용하는 공백은 유의하여야 한다.
[옳은 예]
spam(ham[1], {egg: 2})

[틀린 예]
spam( ham [ 1 ], { egg: 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

 

  • 하지만 콜론과 연산자가 함께 사용될 경우에는, 또 콜론의 연산우선순위가 낮을 경우에는 콜론에 공백을 둘 수 있다.
[옳은 예]
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]

[틀린 예]
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]

 

  • 여는 괄호 앞에는 공백을 두지 않는다.
[옳은 예]
spam(1)
dct['key'] = 1st[index]

[틀린 예]
spam (1)
dct ['key'] = 1st [index]

 

  • '=' 기호를 수직정렬 시키기 위해 큰 공백을 두는 것은 좋지 않다.
[옳은 예]
x = 1
y = 2
long_variable = 3

[나쁜 예]
x             = 1
y             = 2
long_variable = 3

 

기타 사항

  • 아래와 같은 연산자를 사용할 때는 한 칸씩 공백을 두도록 한다.
    (=, +=, -=, ==, <, >, !=, <>, <=, >=, in, not in, is, is not, and, or, not)
  • 다른 우선순위의 연산자를 사용할 경우에는 우선순위가 낮은 연산자 사이에 공백을 두도록 한다.
[옳은 예]
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)

[나쁜 예]
i=i+1
submitted +=1
x = x * 2 - 1
c = (a + b) * ( a - b)

 

  • 함수 사용시에는 colon 뒤에는 공백을 넣고, -> 표현 사이에는 공백을 넣어야 한다.
[옳은 예]
def munge(input: AnyStr):
def munge() -> PosInt:

[나쁜 예]
def munge(input:AnyStr):
def munge()->PosInt

 

  • 함수 사용에서 '=' 기호를 사용해서 keyword argument를 indication할 때에는 공백을 쓰지 않도록 한다.
[옳은 예]
def complex(real, imag=0.0):
    return magic(r=real, i=imag)
    
[나쁜 예]
def complex(real, imag = 0.0):
    return magic(r = real, i = imag)

 

  • 함수 argument annotation 중 '=' 기호를 default value를 나타낼때는 공백을 두도록 한다.
[옳은 예]
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)

 

  • 또 여러개의 명령어를 하나의 줄에 작성하는 것은 추천하지 않는다.
  • 단, if/for/while 문을 간결하게 한줄로 작성이 가능한 경우에는, 사용하여도 무방하지만 권장하지는 않는다.
[옳은 예]
if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three()

[나쁜 예]
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three();

 

Trailing commas(문자열 뒤에 기입하는 쉼표)

  • Trailing comma를 사용하는 것은 자유롭지만, 1개의 요소만 존재하는 튜플을 사용할 경우에는 꼭 넣도록 한다. 또 튜플임을 알 수 있도록 괄호를 작성하는 것이 좋다.
[좋은 예]
FILES = ('setup.cfg',)

[나쁜 예]
FILES = 'setup.cfg',

 

  • 또 추후 버전이 업그레이드 됨에 따라서 요소가 추가될 수 있다는 것을 알리기 위해서 trailing comma를 넣는 것이 좋다.
  • 이 때에는 각 요소를 각각의 줄에 위치시키고, 닫는 괄호 역시 마지막 요소의 아래 행에 위치해야 한다.
[좋은 예]
# Correct:
FILES = [
    'setup.cfg',
    'tox.ini',
    ]
initialize(FILES,
           error=True,
           )
           
[나쁜 예]
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)

 

함수, 변수, 클래스 등의 이름에 대한 규칙

  • 너무나 많은 패키지가 각각의 명명 규칙을 갖고있지만, PEP8에서 추천하는 명명규칙이 따로 존재한다.
  • 따라서 새로 진행하는 프로젝트나 모듈 작성에서는 아래와 같은 규칙을 따를 것을 권장한다.
b (single lowercase letter)
B (single uppercase letter)
lowercase
lower_case_with_underscores
UPPERCASE
UPPER_CASE_WITH_UNDERSCORES
CapitalizedWord
mixedCase (첫 글자가 대문자가 아님)
Capitalized_Word_with_Underscores (ugly!)

 

  • _single_leading_underscore는 내부적으로 사용하는 변수이다. 이 변수는 import * 시에 로딩되지 않는다.
  • single_trailing_underscore_는 파이썬 키워드와 충돌하는 것을 막기 위해 사용된다.
[예]
tkinter.Toplevel(master, class_='ClassName')

 

  • __double_leading_underscore: class attribute를 명명할 때 사용된다(FooBar 클래스 내부의 boo는 FooBAR__boo가 됨).
  • __double_leading_and_trailing_underscore__는 magic 객체라고 불리우며, __init__, __import__, __file__등이 있다.

 

명명시에 피해야 할 문자

  • i(lowercase letter el), O(uppercase letter oh), I(uppercase letter eye)는 사용하지 않도록 한다.

 

패키지와 모듈 이름

  • 모듈은 짧고 모두 소문자여야 한다.
  • 언더스코어는 가독성을 향상시킬 때만 사용 가능
  • C/C++ 모듈의 이름 앞에는 언더스코어가 붙어야 한다 (예, _socket)

 

클래스 이름

  • 클래스 이름은 CapWords로 지어야 한다.

 

예외 이름

  • 예외는 클래스여야 하기 때문에 클래스 이름 작성 규칙을 따른다.
  • 단 Error 접미사를 붙이도록 한다.

 

함수 및 변수 이름

  • 함수이름은 언더스코어로 구분된 소문자(lower_case_with_underscores)를 사용하도록 한다.
  • 변수 이름은 함수 이름 명명 규칙을 따르도록 한다.
  • 이전버전에서 mixedCase를 사용한 경우에는 mixedCase를 따르도록 한다.

 

전역 변수 이름

  • 전역변수 이름은 함수 명명 규칙을 따른다.

 

함수와 메서드 인자

  • 항상 self가 인스턴스 메서드의 첫번째 인자가 되어야 한다.
  • 항상 cls가 클래스 메서드의 첫번째 인자가 되어야 한다.
  • 함수 인자가 파이썬 키워드와 충돌할 경우 single_trailing_underscore_ 를 따르도록 한다.
    (e.g. class_를 사용하는 것이 clss를 사용하는 것보다 낫다)

 

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

  • 언더스코어로 구분된 소문자(lower_case_with_underscores)를 사용하도록 한다.
  • non-public 메서드와 인스턴스 변수에는 _single_leading_underscore를 적용한다.
  • 하위 클래스와 이름 충돌을 피하기 위해서 파이썬의 맹글링 규칙에 따라 __double_leading_underscore 를 사용한다.

 

상수

  • 상수는 대문자로 작성한다(e.g. MAX_OVERFLOW, TOTAL).