메뉴 바로가기 본문 바로가기

Pythonic 한 코드 작성하는 방법 with PEP8

  • 서동근
  • 2023.02.15

Pythonic 한 코드 작성하는 방법 with PEP8


    • 들어가며

귀도 반 로섬(파이썬 개발자)의 중요한 인사이트 중 하나는, “코드는 쓰는 것 보다 읽는 것이 중요하다” 라고 말했습니다.( One of Guido’s key insights is that code is read much more often than it is written.)

따라서 PEP8은 코드의 가독성을 향상시키며, 파이썬 코드의 작성법을 일관적으로 만드는 것을 목적으로 합니다.

코드의 일관성은 매우 중요합니다. 특히나 각자의 개성이 뚜렷하게 드러나는 코딩에서 다른 팀원들과 협업하는 경우에는 디버깅이나 코드 리뷰와 같이 코드 관리 측면에서 더욱 효율적인 성능을 이끌어낼 수 있습니다.

PEP8 규칙을 지키는 것이나, pythonic한 코드를 짜는 것은 반드시 지켜야 하는 규칙은 아니며,

특히나 아래와 같은 상황에선 PEP8 가이드라인을 준수하지 않아도 되는 대표적인 사례들 입니다.

    • PEP8에 따라 코드를 읽음에도, 가이드라인을 적용하는 것이 코드의 가독성을 해칠 경우.
       

    • 과거 PEP를 준수하지 않고 작성한 코드와 일관성을 유지하는 경우. (PEP를 준수하여 코드를 수정할 상황이여도, 과거에 작성한 코드의 스타일을 존중하자)
       

    • 코드 작성시기가 PEP8의 작성 시기보다 앞서며, 코드를 수정할 필요가 없을 경우
       

    • 과거버전의 파이썬으로 작성하여 가이드라인을 준수할 경우, 코드가 작동하지 않아 과거 버전과 호환될 필요가 있는 경우.

저는 여러 PEP8 규칙 중, 제가 직접 코드를 작성하며 많이 쓰이며 협업하며 불편했던 점을 위주로 코드 설명을 드리고자 합니다.

전체적인 내용이 궁금하신 분들은 PEP8 원본을 참고하시기 바랍니다. (https://peps.python.org/pep-0008/)


    • Code layout


    • 들여쓰기

파이썬은 흔히 사용되는 다른 언어와 다르게 들여쓰기로 프로그램 구조를 해석합니다.

들여쓰기를 사용하는 좋은 예시는 아래와 같습니다.

 

함수를 선언하는 부분에서는 함수 내부에 코드과 인자들을 구분하기 쉽게 한칸 더 들여쓰기 해주고,
함수를 실행할때는 함수실행 (1), (2) 처럼 parameter를 정렬하여 가독성을 높여 줍니다.

코드 작성할때 가장 많이 사용하는 문법중 하나인 if문을 사용할 때는, 아래와 같이 사용합니다.

 

if 구문과 함수 내부 코드를 주석을 사용하여 구분하거나,
들여쓰기를 한칸 더 사용하여 구분합니다.

이항연산자에서의 줄바꿈은 아래와 같습니다.

 

첫번째 연산식은 수십년동안 추천된 이항연산자 이후 줄바꿈을 하는 형식입니다.
이 형식은 간단한 연산식임에도 가독성을 해치기 쉽습니다.

두번째 연산식과 같이 수학자들의 전통을 따라 이항연산자 전에 줄바꿈하여, 결과적으로 더 가독성 좋은 코드를 작성할 수 있습니다.


    • 표현식과 공백

정도를 지나침은 미치지 못한 것과 같다 라는 뜻의 과유불급 이라는 사자성어가 있습니다.

 

첫번째 함수 실행이 그 사자성어의 대표적인 예시입니다.
가독성을 위해 공백을 남발하다 보면 오히려 가독성을 해칠 수 있습니다.

두번째 함수 실행처럼 관계없는 공백은 피하는것이 좋습니다.(괄호,중괄호,대괄호 안)

하지만 매개변수 사이엔 ‘,’ 뒤에 한칸의 공백을 줘서 가독성 좋은 코드를 작성할 수 있습니다.

이 공백 선언은 변수를 선언하거나, 값을 할당할때도 아래와 같이 사용합니다. 

 

하지만 한가지 의문구심이 들만한 부분이 있습니다.

i + 1 은 공백으로 구분하여 표기하지만, 어째서 x*2 - 1 에서는 하나밖에 구분하지 않을까요 ?

이는 다른 우선순위의 연산자가 함께 쓰인다면, 가장 우선순위가 낮은 연산자 주변에 공백을 추가하는 것을 고려하여 본인의 판단 하에 사용하기 때문입니다.

이와 동일하게 공백을 사용하지 않는 경우가 하나 더 있습니다.

 

위와 같은 상황입니다.

이는 keyword argument 혹은 기본 parameter 값을 나타내기 위해 ‘=’ 기호 주변엔 공백이 없어야 합니다.


    • 주석 

주석은 많은 개발자 및 연구원들이 코드를 더 쉽게 이해할 수 있게 하기위해 사용하며 주로 협업할때 유용하게 사용되며, 이 주석에 관련된 규칙도 있습니다.

코드와 전혀 상관 없는 주석은 없는것 보다 쓸모 없습니다. (간결성이 떨어짐)

항상 코드가 바뀌고 업데이트 될때 주석을 먼저 적는것을 당부합니다. 

한국인 기준으로, 코드를 읽을 사람이 한국인이라고 120% 확신하지 않는 한 영어로 작성하도록 합니다.

주석은 완전한 문장이어야 하고, 특별한 사유가 없다면 대문자로 적도록 합니다.

마지막 문장을 제외하곤 문장 끝에 두개의 스페이스를 사용하도록 합니다.


    • 인라인 주석

인라인 주석은 코드와 같은 라인에 있는 주석입니다.

인라인 주석은 너무 남발하면 안되며, 코드로 부터 최소 두칸 이상의 공백, # 이후 공백 한칸으로 구분되어야 합니다.

인라인 주석은 명확하지 않으면 오히려 가독성을 떨어뜨릴 수 있으므로 최대한 간결하고 명확하게 끝내야한다.

 



    • 닥스트링

좋은 닥스트링에 관해 깊게 보고싶으시다면 PEP 257 을 추천드립니다. (https://peps.python.org/pep-0257/)

모든 public 모듈, 함수, 클래스, 메소드에 대해 닥스트링을 작성합니다.

Non-public한 메서드에서는 닥스트링이 필요하지 않지만, 해당 함수나 메서드에 대한 설명을 적어야하며, 이 주석은 함수 선언 라인 다음에 위치해야 합니다.

 

위와 같이 여러줄의 닥스트링의 끝내는 “”” 은 독립적인 라인에 있어야 하며, 한줄로 쓰일때는 같은 라인에 놓아야 합니다. 

 


    • 네이밍 작성 규칙

클래스, 함수, 변수 등에 대한 네이밍 개발자들에게 주된 고민거리입니다.

명시적이며 간결하게 네이밍 하는것은 꽤나 어려운 일이기 때문이죠,

이번 파트에서 네이밍에 관련한 고민거리가 조금이나마 덜어지셨으면 좋겠습니다 ! :)

우선 I(대문자 아이), l(소문자 엘), O(대문자 오) 와 같이 서로 헷갈릴 거나, 1 혹은 0과 구분하기 어려운 문자는 한글자 변수로 사용하지 않도록 해야합니다.

패키지와 모듈 이름에 대한 규칙은 아래와 같이 있습니다.

    1. 짧으며 모두 소문자인 이름을 가져야하며

    2. _(언더바) 는 가독성을 향상시킬 수 있을 경우 모듈의 이름에 사용될 수 있고

    3. 패키지 이름 또한 짧으며 모두 소문자여야 하지만, _(언더바) 는 사용될 수 없다

    4. C / C++ 모듈은 이름 앞에 _(언더바) 가 있어야 한다.


클래스 이름은

    1. CapWords 형태를 사용해야 하며

    2. 클래스 내부에서만 사용된다면 앞에 _(언더바) 를 사용해야합니다.

함수 및 변수 이름 매우 간결합니다.

    1. 함수 및 변수 이름은 가독성을 중요시 하기 때문에, _(언더바) 를 사용하여 구분합니다.

    2. mixedCase 는 오로지 이전 버전의 호환성을 유지할 필요가 있을 경우만 허락됩니다.

그 외에도 모듈 안에서만 사용되는 변수나 함수 앞에는 _(언더바) 를 붙여 작성하여 줍니다.
ex) _temp_list = []
이렇게 앞에 _(언더바) 를 붙여 협업하는 다른 동료에게 ‘이 변수는 모듈 내부에서만 사용합니다’ 라는 힌트를 줄 수 있습니다.

그 외에 권장 사항은 

if not foo is None: …

보다 

if foo is not None: …

같이 작성하거나,

lambda 함수보단 def를 사용하는 방법등 여러가지 규칙들이 있습니다.

관심이 있으시다면 PEP8 원본을 찾아보시는걸 추천드립니다 (https://peps.python.org/pep-0008/)

또 그 외에도 python 모듈로 pep8을 설치하여 pep8 (python file name).py 를 입력하면 아래와 같은 위반 보고서를 얻을 수 있습니다.

 


PEP8 외에도 python 스럽게 작성하는 문법들이 있습니다.

    • list comprehension

기존의 list를 활용하여 다른 list를 만들거나, 간단하게 list를 생성할 수 있습니다.

일반적으로 사용하는 for + append 보다 속도가 빠르며 가독성이 좋습니다.

아래는 평범하게 0부터 9까지의 list를 만드는 방법입니다.

 

파이썬에서는 아래와 같이 가독성 좋으며 간단하게 만들 수 있습니다.



list comprehension에 if문을 활용하여 홀수만 있는 list를 만들 수 있습니다.

 

 


    • join

또, 문자열을 나눠 list에 저장해뒀다가 합쳐야할 때가 있습니다.

그땐 python의 join함수를 이용하여 간단하게 해결할 수 있습니다.


 

이 함수를 모르는 사람들은 3번째 줄처럼 코드를 작성할 것 입니다.

하지만 join함수를 사용하면 간단하게 단어들을 연결할 수 있습니다.


    • generator

마지막으로 알아볼 pythonic 한 코드는 generator 입니다.

사실 generator를 쓴다고 가독성이 좋아지거나, pythonic 해지진 않습니다.

그냥 평범하게 사용하는 list에서 형식만 달라진 것 이니까요.

하지만 대규모의 data를 처리할 상황에서 data가 많아질 수록 메모리를 많이 차지하는 list형식보다, generator 형식으로 처리하는게 메모리 측면에서 훨씬 더 효율적일테니까요.

 

LT_list 는 평범한 list 타입이고, GT_list는 generator 타입입니다.

이 둘의 메모리 사이즈는 아래와 같이 차이가 납니다.

 

하지만 이는 data가 많아지면 많아질 수록 더욱 심해집니다.

range 값을 1000000 에서 1000000000 으로 변경하니 그 차이는 더욱 심해집니다.

 

간단하게 형식만 변경하여 메모리측면에서 엄청난 효율을 올릴 수 있으니 한번 사용해보시기 바랍니다.


    • 마치며

Python을 더욱 Pythonic 하게 만드는 규칙과 이전보다 더 효율적이며 가독성 좋게 코드를 작성하는 방법에 대해 알아봤습니다.
Python은 Pythonic이라는 말이 있을 정도로 Python 스러움을 중요시하는 언어입니다.

Python 스러운 언어를 작성하면 가독성과 효율성이 좋아지며 여러 이점을 만들 것 입니다.

하지만 위 규칙은 ‘반드시’ 준수해야 하는 규칙은 아닙니다. 이전 코드에서 적용한 규칙이 있다면 그 규칙을 따르는것이 바람직합니다.

앞으로 늘어가는 Python 개발자와 기존 Python 개발자들이 더욱 더 Pythonic 하게 코드를 작성하는 눈부신 발전을 기대해봅니다.

마지막으로 Python에 이스터에그 처럼 보이는 import this 모듈로 마무리하겠습니다.

The Zen of Python, by Tim Peters


Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren't special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one-- and preferably only one --obvious way to do it.

Although that way may not be obvious at first unless you're Dutch.

Now is better than never.

Although never is often better than *right* now.

If the implementation is hard to explain, it's a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea -- let's do more of those!


CUBOX는 NIST에서 주관하는 얼굴 인식 대회인 FRVT(얼굴 인식 알고리즘 기업 테스트, Face Recognition Vendor Test)에서 1:1, 1:N 모두 세계 1위, 국내 1위 성적을 보유하고 있습니다. (2021년 11월) 이러한 기술력을 인정 받아 인천공항, 정부 청사의 얼굴 출입 시스템을 직접 구현하여 운영하고 있습니다. CUBOX AI LAB은 Face re-identification, Face detection, Face Mask Effect, Face Anti-Spoofing 등 얼굴 인식 기술 전반에 대한 독자적인 모델 연구를 진행하고 있으며, 관련 데이터셋 구축 사업 역시 진행하고 있습니다.
본문의 글이나 CUBOX AI LAB 연구에 대한 문의사항이 있으시거나 AI LAB과 함께하고 싶으신 분들은 언제든지 연락 주시기 바랍니다. 

 

    • 참고자료

https://peps.python.org/pep-0008/

https://programmers.co.kr/learn/courses/4008

 

https://docs.python.org/3/glossary.html#term-iterable

 

About Author

 

서 동 근

Pro, AI 3팀

dgseo@cubox.ai


TAG