파이썬 코딩 스타일 가이드

한글판 johnsonj 2003.11.21

파이썬 코드의 형식에는 수 많은 방식이 있다. 이런 자유를 남용하여 읽기 어렵게 만들고 그리하여 유지보수하기가 힘들게 코드를 작성하는 프로그래머가 많다. 적절하게 코드를 포맷하는 방법에는 여러가기 있겠지만, 여기에서는 실제로 사용할 때 쓸모가 있을 만한 가이드라인을 제공한다. 맹목적으로 따를 필요는 없지만, 어설픈 형식에는 확실하게 어깃장을 놓아볼 생각이다. 이 가이드라인중 일부는 크게 쓸모가 없어 보일 수도 있지만, 코드를 읽어 보면, 확실하게 그 차이를 느낄 수 있을 것이다.

다음에서, 각 항목은 설명다음에 그에 관련된 코드가 따른다. 이 코드로 문제를 지적하면서 코드를 교정하겠다. 항목에 코드를 짝짓는 일은 여러분의 책임이다. 모쪼록 이렇게 해서 재미있게 이 스타일 가이드를 읽기를 바란다:-) 일반적으로, 한 섹션에서 앞의 항목은 뒤의 항목보다 더 중요하며 그리고 더 자주 일어나는 에러를 나타낸다.

또, 가장 단순한 스타일의 실수를 잡는 것을 돕기 위하여 자동화된 스타일 점검기 프로그램을 제공한다. 이 프로그램은 에러 모두를 잡아내는 것은 아니지만, 일반적인 에러들을 많이 잡아낸다. 코드를 제출하려면 먼저 스타일 점검기에 그 코드를 넣어 테스트해 볼 필요가 있을 것이다; 실패하면, (스타일 점검기에 버그가 있다는 것을 확신시켜 주지 못하는 한, 물론 그럴 수 있다) 평가 대상이 되지 못한다. 파이썬 스타일 점검기는 (물론) 파이썬으로 작성되었다;-). 먼저 내려 받은 다음, "~/bin" 디렉토리에 넣고 나서 (디렉토리를 하나 만들고 탐색 경로에 넣어두면 된다) 다음과 같이 하자:

    chmod +x ~/bin/python_style_check
그 다음에, 파일 "foo.py"의 스타일을 점검하려면, 다음과 같이 한다:
    python_style_check foo.py
에러가 많이 보고되더라도 놀라지 말자; 그냥 파일을 찾아 들어가 고치면 된다. 어떤 줄에서는 갖가지 모습으로 규칙을 범하고 있을 것이다; 그 모든 실수들을 고쳐야 한다. 처음에는 이 프로그램이 마음에 들지 않겠지만, 그 결과로 코드가 훨씬 읽기에 편하게 된다는 사실을 명심하자. 프로그램에서 버그를 발견했다고 생각하면, 즉시 알려주기를 바란다; 이 프로그램은 개발중인 작품이다. 주의할 것은 스타일 점검기가 가끔씩 멍청해서 주석이나 기호문자 문자열 안에 있는지 알지 못하므로, 그러한 경우에는 실제로는 에러가 아닌데도 보고하는 경우가 있다. 그렇다면, 그냥 무시하면 된다. 스타일 점검기는 또한 여러 자바 소스 코드 파일도 다룰 수 있다는 것을 주목하자. 그래서 따로따로 파일을 지정하는 대신에 다음과 같이 할 수 있다:
    % python_style_check *.py
물론, 파일이 .py로 끝나지 않으면 따로따로 다 지정해야 한다.


일반적으로 많이 저지르는 스타일 실수

다음에 지적하는 실수들은 거의 보편적이라고 할 정도로 아주 자주 일어난다. 그러므로, 특히 주의해서 피해 주기를 바란다. 링크를 따라가서 아래에 기술된 설명을 보도록 하자. 별표(*)가 뒤에 붙은 스타일 실수는 스타일 점검기로 잡을 수 있다.
  • TABS*   코드에 탭 문자를 사용한다.
  • OPERATOR_SPACE*   연산자 양쪽에 공간을 하나씩 두지 않는다.
  • COMMA_SPACE*   쉼표 뒤에 공간을 두지 않는다.
  • LINE_LENGTH*   78 문자가 넘는 줄을 작성한다.
  • USAGE_STMT   사용 설명이 빠졌거나 부적절하다.
  • BLANK_LINES   함수나 프로그램에 너무 많은 또는 너무 적은 빈 줄을 사용한다.
  • COMMENTS_FULL_SENTENCES   불완전한 문장으로 주석을 작성한다.
  • COMMENTS_GRAMMATICAL   문법적으로 옳지 않거나 철자가 바르지 못한 주석을 작성한다.
  • COMMENT_SPACE*   열림-주석 심볼 "/*" 뒤에 닫힘-주석 심볼 "*/" 앞에 공간을 하나씩 두지 않는다.
  • DOCSTRINGS   함수, 클래스, 혹은 모듈의 머리부에 적절한 문서화문자열 주석을 작성하지 않는다.
  • EXCEPTIONS_CATCH_ALL   일망타진(catch-all) 예외 처리를 사용한다.

스타일 실수의 범주

일반

  • [TABS]

    절대로 탭 문자(ascii 0x9)는 사용하지 말자! 사람마다 탭 설정을 다르게 사용한다. 너비가 2인 탭으로 잘 작동하는 듯 보이는 코드라도 너비가 8인 탭에서는 문제가 된다. (추천해 마지 않는) 이맥스를 사용한다면, 다음 줄들을 .emacs 파일에 넣어두자:

        ;; Load python mode.  The path will depend on the installation.    (load-file "/home/cs11/emacs/python-mode.el")    ;; Make files that end in .py automatically go into python mode.    ;; If your file doesn't end in ".py" then you'll have to do    ;; "M-x python-mode" manually after you load up the file.    (append '(("\\.py\\'" . python-mode)) auto-mode-alist)    ;; Set up initialization parameters for python mode:    (setq python-mode-hook          '(lambda () (progn                        (set-variable 'py-indent-offset 4)                        (set-variable 'py-smart-indentation nil)                        (set-variable 'indent-tabs-mode nil) )))
    이맥스에서 파이썬 코드를 편집하면서 탭 키를 치면, 자동으로 그 코드를 그 줄에서 합리적인 위치까지 들여쓰기 해 준다. 앞의 코드를 (이 코드는 emacs-lisp 코드이지만, 신경쓰지 말것) .emacs 파일 안에 넣어 두면, 탭 키를 치더라도 실제로 코드에 탭 문자가 들어가는 대신에, 그냥 네 개의 공간을 넣는다.

  • [OPERATOR_SPACE]

    언제나 다음 연산자들 주위에는 각 양쪽에 공간을 하나 두자: 할당 연산자 (=, +=, 등등), 비교 연산자 (==, <, >, !=, <>, <=, >=, in, not in, is, is not), 불리언 연산자 (and, or, not), 그리고 산술 연산자. 예제:

    i = j + 1               # 불가 i=j+1        submitted += 1          # 불가 submitted+=1        x = x * 2 - 1           # 불가 x=x*2-1        hypot2 = x * x + y * y  # 불가 hypot2=x*x+y*y        c = (a + b) * (a - b)   # 불가 c=(a+b)*(a-b)

    어떤 사람들은 * 또는 / 양쪽에 공간을 두지 않는 편을 더 좋아하지만, + 그리고 -에는 우선순위에 대한 힌트로서 공간을 두기를 좋아한다. 그렇지만 이는 권장할 수 없다. 그렇지만, 간단한 증/감 연산에 대한 배열 첨자에서는 양쪽에 공간을 생략해도 좋다:

        b = a[i-1]

    불행하게도 현재 버전의 스타일 점검기는 무조건 이에 표식을 한다.

  • [COMMA_SPACE]

    쉼표 다음에는 언제나 공간을 하나 두자.

  • [LINE_LENGTH]

    주변에는 여전히 80개의 문자로 제한되는 장치들이 많다 (특히 프린터). 그런 장치에 대하여 기본 줄바꿈 값은 보기에 않 좋다. 그러므로, 줄들을 모두 78 자까지 제한하자.

    긴 줄을 감싸는 유력한 방법은 파이썬이 활괄호, 각괄호, 반괄호 안에서는 묵시적으로 줄이 연속되어 있다고 간주하는 점을 이용하는 것이다. 필요하다면, 표현식 주위에 괄호를 하나 더 덧붙여도 좋지만, 역사선을 이용하는 것이 더 보기 좋은 경우도 있다. 반드시 연속된 줄을 적절하게 들여쓰기 하자. 예제 약간:

        class Rectangle(Blob):        def __init__(self, width, height,                     color='black', emphasis=None, highlight=0):            if width == 0 and height == 0 \               and color == 'red' and emphasis == 'strong' \               or highlight > 100:                raise ValueError, "sorry, you lose"            if width == 0 and height == 0 and (color == 'red' \                                               or emphasis is None):                raise ValueError, "I don't think so"            Blob.__init__(self, width, height,                          color, emphasis, highlight)

    어떤 경우에는, 명시적인 줄 연속 문자가 불필요한 경우가 있다. 잘 모르겠으면, 어쨌거나 사용하자. 또, 기다란 불리언 표현식에는 (a and b and c...) "and" 또는 "or"를 줄의 끝이 아니라 앞에다 두자; 이렇게 하면 표현식이 앞의 줄에서 계속된다는 사실을 확실히 알 수 있다.

  • [USAGE_STMT]

    프로그램이 올바르지 않은 인자로 호출되면, 그 사실을 탐지해서 터미날에 사용법을 인쇄해 주어야 한다. 사용 방법에는 반드시 그 프로그램의 이름이 들어가야 한다. 가장 쉽게 하는 방법은 sys.argv[0]를 이용하는 것이다.

        import sys, re    # 완전한 프로그램의 경로이름을 벗겨내고 프로그램 이름만 남긴다.    prog_name = re.sub(".*/", "", sys.argv[0])    usage = "usage: %s input_filename output_filename" % prog_name    if len(sys.argv) != 2:       print usage       sys.exit(1)
    주목할 것은 인자들이 연상작용을 돕는 이름이 있다는 것이다. 사용법 메시지가 아주 길면, 문서화문자열 안에 넣자 (아래 참조).

  • [BLANK_LINES]

    최고-수준의 함수와 클래스 정의는 최소한 두 개의 빈 줄로 가르자. 클래스 안에서 메쏘드 정의를 가르는 것도 역시 빈 줄 두개로 가른다. 그러나 어떤 경우에는 빈 줄 한개도 괜찮다. 관련 함수를 모아 놓은 그룹이라면 빈 줄을 더 사용하여도 좋다 (그러나 너무 지나치면 안된다). 또 주석을 두어 함수의 그룹을 갈라도 좋다. 예.

        # 다음 함수들은 위젯 클래스를 위하여 인터넷 접근을 제공한다.

    정말로 중요한 섹션이라면, 또는 클래스 머리부라면, 다음과 같이 하자:

        #    # 이 클래스 위젯이 구현하는 객체는    # 갖가지 종류의 일들을 할 수 있다.    #

    즉. 즉 머리부의 윗쪽과 아래쪽에 빈 주석 줄 하나씩을 두자.

    기다란 함수나, 또는 함수 안에서 섹션이 길다면, 주석을 함수/블록의 끝에다 다른 것도 좋은 생각이다, 예.

        def foobar(x, y, z):        # 다음에 코드가 2000 줄 따른다...        return 1    # foobar 끝	

    비슷하게, "# end if", "# end while", 등등을 두어도 좋다. 더 좋은 해결책은 이것이 필요하지 않도록 가능하면 함수와 블록을 짧게 유지하는 것이다.

    함수에서 논리적 구획을 나타내려면 빈 줄들을 사용하자. 또한 각 if/while/for 서술문 앞에다 빈 줄들을 두어서 그를 둘러싼 코드와 논리적으로 구별하기를 즐기는데, 경험상 이렇게 하면 코드가 더 읽기 쉽다.

    코드에서 서로다른 구역을 분별할 필요가 확실하지 않는 한 코드 구역 사이에 너무 많은 빈줄(> 2)을 놓지 말자.

  • [INDENT_CONSISTENT]

    들여쓰기 수준은 일관성이 있어야 한다. 한 수준 들여쓰기에 4개의 공간을 선호한다.

  • [MAGIC_NUMBER]

    둘러싼 코드와 별 관련이 없는 기다란 숫자를 파일에 넣는 것을 피하자. 이는 "마법의 수(magic number)"라고 알려져 있다 (역주 : 물리학 용어에서 유래, 양성자의 수 또는 중성자의 수가 미리 정해진 어떤 값을 가지면 원자핵이 특별히 안정된다. 그렇지만 처음 관찰되었을 때는 왜 그런지 잘 설명할 수가 없어서 그런 수를 마법의 수(magic number) 라고 불렀다. 마법의 수를 가지면 존재 확률이 높아짐을 비유해서, 각종 프로토콜에서 서로 간에 신분을 확인하는 숫자를 마법의 수라고 일컫는다.) 대신에 그 마법의 수를 파일의 위에다 정의해 두자.

  • [USELESS_CODE]

    아무 기능이나 효과도 없는 코드를 넣지 말자. 그것이 디버깅 코드라면, 확실하게 그렇다고 표식을 해 두어야 한다.

  • [STMTS_ON_LINE]

    한 줄에 여러 서술문을 두지 말자. 아주 간단한 서술문이라고 할지라도 안된다. 그저 혼란스럽고 읽기가 어렵게 만들 뿐이다. 비슷하게, 다음도 별로 마음에 안든다:

        if not line: break

    그 보다 다음을 더 선호한다:

        if not line:        break

    명심하자: 새줄문자(newlines)에는 세금이 없다. 한 줄에다가 억지로 많이 구겨 넣으려고 하지 말자.

  • [BAD WHITESPACE]

    다음의 장소에는 공백(whitespace)을 사용하지 말자:

    • 활괄호, 각괄호, 또는 반괄호 바로 안쪽에서, 다음과 같이:
          spam( ham[ 1 ], { eggs: 2 } )

      언제나 다음과 같이 작성하자:

          spam(ham[1], {eggs: 2})
    • 쌍점, 쌍반점, 또는 쉼표 바로 앞에서, 다음과 같이:
          if x == 4 :        print x , y        x , y = y , x

      언제나 다음과 같이 작성하자:

          if x == 4:        print x, y        x, y = y, x
    • 함수 호출의 인자 목록을 시작하는 여는 괄호 바로 앞에서, 다음과 같이
          spam (1)

      언제나 다음과 같이 작성하자

          spam(1)
    • 지표화나 조각썰기를 시작하는 여는 괄호 바로 앞에서, 다음과 같이:
          dict ['key'] = list [index]

      언제나 다음과 같이 작성하자

          dict['key'] = list[index].
    • 다른 것과 줄을 맞추기 위해 할당 (또는 다른) 연산자 주위에 과도한 양의 공간, 예를 들어:
          x             = 1    y             = 2    long_variable = 3

      최고로 좋은 규칙: 연산자를 8개 또는 9개의 공간을 두고 이동해야 한다면, 시간을 낭비하지 말자. 그렇지 않으면, 정렬하자. 예., 다음은:

          x = 1    foo = 2    fudge = 5

      다음과 같이 바꾸자.

          x     = 1    foo   = 2    fudge = 5

      그러나 다음은

          x = 1    y = 2    this_variable_name_is_really_long = 3

      그대로 두자. 이는 스스로 내려야 하는 결단(judgment call)의 문제이다.

  • [KEYWORD_SPACES]

    '='가 키워드 인수나 기본 매개변수 값을 나타내는데 사용되면 '=' 주위에 공간을 사용하지 말자. 예를 들면:

        def complex(real, imag=0.0):        return magic(r=real, i=imag)
  • [PRECEDENCE]

    모든 경우에 덧셈/뺄셈과 할당 서술문 보다 곱셈/나눗셈이 우선순위가 있음을 괄호로 둘러 연산자 우선순위를 나타내자.

  • [IMPORT]

    일반적으로, "from X import *"로 형태로 사용하는 것을 피하자; 다음과 같이 하든가:

        from X import Y  # 많이 사용되는 함수만 하나 수입

    또는 다음과 같이 하자:

        import X # 사용할 모듈에서 수 많은 함수가 필요할 때.

    또, 클래스나 함수 안에서 "import X"나 "from X import Y"를 사용하지 말자. 꼭 그렇게 사용해야 할 경우를 보지 못했고, 그렇게 하는 것은 혼란만 초래할 뿐이다. 모든 수입 서술문은 모듈의 최상위 수준에 그리고 파일의 최상단에 두자. 그렇게 해 두어야, 어디에서 찾아 보아야 할지 알 수 있다. 어떻게 형식화할지는 자신의 자유이다

        import X, Y, Z

    또는

        import X    import Y    import Z

    보통 한 번 쓰고 버릴 스크립트에는 앞의 형식을 커다란 프로젝트에는 뒤의 형식을 사용하는 경향이 있다.

주석

  • [COMMENTS_FULL_SENTENCES]

    주석이 구이거나 문장이라면, 소문자로 시작하는 식별자가 아닌 한 첫 단어는 반드시 대문자여야 한다 (식별자의 격을 절대로 바꾸지 말 것!). 되도록 완벽한 문장이면 더 좋다. 마침표 뒤에는 공간을 두 개 사용해야 한다. 이상적으로, 식별자를 가리키려면 따옴표를 두르자, 예.

        # 변수 'nitems'은 스택에 있는 항목의 개수를 나타낸다.

    주석이 아주 짧다면, 완전한 문장이 될 필요가 없으며, 또는 마침표로 끝날 필요가 없다 예.

        i = 1  # 회돌이 지표
    이는 이른바 "인라인 주석(inline comment)"이라고 부른다. 무언가를 기술할 때만 이를 사용하자. 즉, 위의 코드 조각에서 "변수 'i'는 회돌이 지표를 나타낸다"와 같이 말할 때만 사용하자.

  • [COMMENT_GRAMMATICAL]

    주석은 올바르게 철자가 되어야 한다 (오타 불가) 그리고 문법적으로 옳아야 한다. 고등하고 영어 선생님처럼 굴고자 하는 것이 아니라, 철자도 틀리고 문법도 안 맞고 게다가 오타까지 있는 주석을 읽는 것은 정말로 불쾌한 일이다.

  • [COMMENT_SPACE]

    여는-주석 사인 뒤에는 늘 공간을 남겨두자 예.

        # 이 주석을 읽기 쉽다.    #이 주석은 읽기 어렵다

  • [COMMENT_NON_OBVIOUS]

    정황(context)으로 미루어 완전히 짐작하기 어려운 것이면 모두 주석을 달자. 특히, 사용중인 코드나 알고리즘이 꼼수적이라면 무조건 주석을 달자. 또 각 함수의 시작부에 함수가 무슨 일을 하는지 기술하는 주석을 달자. 의심스러우면, 가능한한 주석을 달자.

  • [COMMENT_REDUNDANT]

    너무나 당연한 것은 다시 주석을 달면 안된다. 이는 특히 인라인 주석에 흔하다. 예제:

        x = x + 1   # x를 증가시킨다
  • [COMMENT_MEANINGLESS]

    의미없는 주석은 달지 않는다 예.

        i = 1   # i
    웃지 말것; 실제로 이런 것들을 본 적이 있다.

  • [COMMENTS_CONSISTENT_WITH_CODE]

    코드와 모순되는 주석은 달지 않는 만 못하다. "코드가 변경되면 언제나 최우선으로 주석을 최신으로 유지하자!"

  • [COMMENT_INDENT]

    언제나 둘러싼 코드 만큼 같은 정도로 코드를 들여쓰자.

  • [COMMENT_INLINE]

    편의를 위해 인라인 주석을 되도록이면 정렬하자. 다른 말로 하면, 다음과 같이 하면 안 되고:

        x = x + 1       # x에 대한 멋진 주석    y = y + 1   # y에 대한 멋진 주석
    대신에, 다음과 같이 하자:
        x = x + 1       # x에 대한 멋진 주석    y = y + 1       # y에 대한 멋진 주석

  • [COMMENT_PRECEDING]

    피할 수만 있다면 앞의 코드에 적용되는 주석을 달지 말자. 현재 코드 줄이나 또는 바로 다음에 따라오는 코드 줄들을 가리키는 주석을 달려고 노력하자.

  • [COMMENT_BLOCK]

    블록 주석은 일반적으로 뒤에 따르는 코드의 일부 (또는 모두)에 적용된다. 그리고 그 코드와 같은 수준으로 들여쓰기 된다. (주석 안에서 들여쓰기된 텍스트가 아닌 한) 블록 주석의 각 줄은 #와 공간 한개로 시작한다. 블록 주석 안에서 문단은 한 개의 #를 담은 줄로 갈라진다. 블록 주석은 위와 아래에 빈 줄이 있으면 아주 좋다 (또는 새로운 함수 정의의 섹션이 시작되는 곳에 위치한 블록 주석이라면 위에 두 줄 그리고 아래에 한 줄도 좋다). 한개의 #를 가진 줄 하나로 블록 주석을 시작하고 끝내면 좋다; 이는 개인적인 선호의 문제이다. 다른 말로 하면, 블록 주석은 다음과 같이 보인다:

        #    # 빈 줄 다음에 첫 줄이 온다.    #    # 각 문단은 또 빈 줄로 갈라진다,    # 그리고 끝에는 빈 줄이 하나 있다.    #
    클래스나 함수 시작 또는 파일의 상단에 놓인 블록 주석은 반드시 문서화문자열이 되어야 한다 (아래 참고).

문서화 문자열

  • [DOCSTRINGS]

    모든 모듈은 일반적으로 문서화문자열이 있어야 한다. 그리고 모듈에 수출된 모든 함수와 클래스도 역시 문서화 문자열이 있어야 한다. (__init__ 구성자를 비롯하여) 공개 메쏘드 또한 문서화 문자열이 있어야 한다. 잘 모르겠으면, 문서화 문자열을 모든 함수에 덧붙이자. 그렇지 않으면, 어쨌든 함수의 목적을 나타내는 주석을 달아야 한다. 그러므로 문서화문자열을 덧붙이지 않을 까닭이 없다.

    (독립-실행 프로그램인) 스크립트의 문서화문자열은 반드시 그의 "사용방법" 메시지가 사용이 가능하여 하며, 스크립트가 그릇된 인자로 혹은 인자가 없이 호출되면 인쇄되어야 한다 (위 참고).

    일관성을 위하여, 언제나 문서화문자열 주위에는 """삼중 겹 따옴표"""를 사용하자. 이렇게 하면 문서화 문자열을 여러 줄에 걸쳐 넣을 수 있다.

함수

  • [FUNCTION_DECOMPOSITION]

    주저하지 말고 함수를 적절한 곳마다 수 많은 자잘한 함수로 분해하자. 길이가 페이지를 넘어가는 함수는 작성하지 말자.

예외 처리

  • [EXCEPTIONS_CATCH_ALL]

    Don't do this:

        try:        # 코드는 여기에 둔다    except: # 모든 예외를 잡는다        pass

    현재 상황에 딱맞는 에러 처리 코드를 구현할 생각이지만, 당장은 그렇게 하고 싶지 않다면, 다음과 같이 작성하자.

        try:        # 여기에 코드를 둔다    except:  # 예외를 모두 잡는다        raise  # 잡은 예외를 다시 일으킨다

    이 모듈의 코드가 늘어나면 그 때 에러를 잡아 일반적인 방식으로 처리하자. 더 좋은 방법은, 각 예외에 대하여 따로따로 이렇게 하고 그리고 나중에 이를 고치면 얻는 효과에 대하여 주석을 다는 것이다:

        try:        # 여기에 코드를 둔다    except FooError:        # 수정요망(FIXME): 나중에 적절한 에러 처리를 구현할 것.        raise FooError # 해당 예외를 다시 일으킨다

    에러를 전혀 다루고 싶지 않다면, 절대로 안에다 'try: except:' 조건을 두지 말고, 나중을 위해 주석을 붙여 두자:

        # 수정요망(FIXME): 함수 bar()가 일으키는 FooError를 잡을 것.


 

출처 : http://home.hanmir.com/~johnsonj/etc/CS%2011%20Python%20track%20coding%20style%20guide.htm

'programming > python' 카테고리의 다른 글

SMTP 인증에 관한 팁  (0) 2004.01.28
파이썬 스타일 지도서  (0) 2004.01.27
특정 달의 날짜 수 구하기  (4) 2004.01.27

+ Recent posts