Skip to content

2017 03 14 Python 스타일

krikit edited this page Mar 14, 2017 · 1 revision

2줄 요약

  • PEP8을 준수하고 커밋 전에 pylint로 점검하자.
  • unicode literals, print function으로 python3 시대를 대비하자.

PEP8

  • Python은 언어 차원에서 스타일을 강제하진 않지만 (indentation만큼은 강제함) 표준 가이드라인이 있습니다.
  • PEP8
    • 너무 길면 우선 이것만 읽고 pylint가 알려주는 데로 수정합니다. (처음에는 엄청난 에러에 압도되지만 차근차근 하다보면 어느새 PEP8에 맞춰진 자신을 발견하게 됩니다.)

pylint 설치 및 사용법

  • yum, apt-get, brew 등을 통해 설치해도 되고, pip를 통해 설치해도 됩니다.
  • 다음과 같이 실행합니다.
$ pylint -rn your_python_code.py

No config file found, using default configuration
************* Module your_python_code
I:396, 0: Locally disabling global-statement (W0603) (locally-disabled)
I:564, 0: Locally disabling broad-except (W0703) (locally-disabled)
W:373, 0: TODO: configurable for a collection via file.cfg (fixme)
C:  1, 0: Too many lines in module (1459/1000) (too-many-lines)
R:918, 0: Too many local variables (16/15) (too-many-locals)
  • "-rn" 옵션은 "--reports=n"와 같은데 마지막에 리포트를 출력하지 말라는 옵션입니다.
    • 리포트 때문에 에러 메세지가 밀려 올라가 볼 수 없기 때문입니다.
  • 첫 줄의 "No config file found, ..."와 같은 메세지는 설정 파일이 없어서 기본 설정으로 실행했다는 것입니다.
    • 팀 혹은 프로젝트에서 사용하는 특별한 스타일이 있는 것이 아니라면 설정을 권장하지 않습니다.
  • "I:396, ..."부터 한 라인에 하나의 에러 메세지를 보여줍니다.
    • 메세지를 보면서 하나하나 잡으면 됩니다. ;)
    • false alarm 혹은 도저히 어쩔 수 없는 경우 아래와 같이 suppress 합니다. (그래도 "I"와 같이 나옵니다.)
global _TRG_LOCK    # pylint: disable=global-statement

String vs Unicode

  • python2로 한글 텍스트를 다루다보면 unicode('가나다', 'UTF-8'), '가나다'.encode('UTF-8'), '가나다'.decode('UTF-8') 명령어를 왔다갔다 하며 머리를 쥐어뜯어 본 적이 있을겁니다.
  • 그나마 가장 현실적인 해결책은 "파일 IO를 제외하고는 전부 유니코드를 사용하라"라는 idiom일 겁니다.
  • python3에서는 '가나다'는 문자열이고 유니코드입니다. python2에서는 '가나다'는 문자열은 맞지만 byte array입니다. python3에서는 문자열(유니코드)과 byte array를 구분하고, byte array의 경우 명시적으로 b'가나다'와 같이 사용해야 합니다.
  • 이렇게 python2에서 python3처럼 문자열을 기본적으로 유니코드를 사용하도록 하는 마법의 선언이 있습니다.
from __future__ import unicode_literals
  • 그리고 유니코드와 관련된 참고할 만한 cat.py 프로그램입니다. (안심하세요 pythonic합니다. ;)
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
 
 
"""
cat
__author__ = 'krikit ([email protected])'
__copyright__ = 'Just Copyleft! No right reserved.'
"""
 
 
###########
# imports #
###########
from __future__ import unicode_literals
from __future__ import print_function
 
import codecs
import logging
logging.basicConfig(level=logging.INFO)
import optparse
import sys
reload(sys)
sys.setdefaultencoding('UTF-8')    # pylint: disable=no-member
 
 
########
# main #
########
def main():
    """
    cat
    """
    for line_num, line in enumerate(sys.stdin, start=1):
        line = line.rstrip('\r\n')
        logging.debug('%d: %s', line_num, line)
        print(line)
 
 
if __name__ == '__main__':
    _PARSER = optparse.OptionParser(description='cat')
    _PARSER.add_option('--input', help='input file <default: stdin>', metavar='FILE')
    _PARSER.add_option('--output', help='output file <default: stdout>', metavar='FILE')
    _OPTS, _ = _PARSER.parse_args()
    if _OPTS.input:
        sys.stdin = codecs.open(_OPTS.input, 'rt', encoding='UTF-8')
    if _OPTS.output:
        sys.stdout = codecs.open(_OPTS.output, 'wt', encoding='UTF-8')
    main()
  • open('file.txt') 대신 codecs.open('file.txt', 'rt', ecoding='UTF-8')을 사용합니다.
  • stdin, stdout으로 입축력 시 인코딩을 명시하기 위해 "export PYTHONIOENCODNG=UTF-8"이라고 환경 변수를 지정하거나, 위와 같이 "sys.setdefaultencoding('UTF-8')"이라고 코드에 명시해 줍니다.

Print Function

  • python2에서 print는 statement인 반면 python3에서는 하나의 함수입니다.
  • python2에서 print 함수를 사용하기 위해서는 아래 마법의 선언이 있습니다.
from __future__ import print_function

FAQ

  • sys.stderr로 출력하고 싶어요.
# python 2
print >> sys.stderr, 'Hello World'
  
# python 3
print('Hello World', file=sys.stderr)
  • 새 줄로 넘기지 않고 연달아 출력하고 싶어요.
# python 2
print 'Hello',
print 'World'
 
# python 3
print('Hello', end=' ')
print('World')
Clone this wiki locally