What I Learn Today

Start Date : 2022/02/07 ~

창고/Meta PEPs (about PEPs or Processes)

[PEP 8 #3] PEP 8 - 네이밍 작성 규칙

HannaDev 2022. 3. 12. 00:21
📬 현재 권장되는 Python 네이밍 표준에 관한 내용입니다.

 

<PEP 8 시리즈> Index

  1. PEP 8 - Python 코드에 대한 스타일 가이드라인 
  2. PEP 8 - Code Lay-out
  3. PEP 8 - 네이밍 작성 규칙
  4. PEP 8 - 프로그래밍 권장사항 

<목차>

  1. 가장 중요한 원칙
  2. 표현 (Descriptive) : 네이밍 스타일
  3. 규정 (Prescriptive) : 네이밍 스타일
    • 피해야할 이름
    • 패키지와 모듈 이름
    • 클래스 이름
    • 타입 변수 이름
    • 예외 이름 (Exception Names)
    • 전역 변수 이름
    • 함수 및 변수 이름
    • 함수와 메서드의 독립변수
    • 메서드 이름 그리고 인스턴스 변수
    • 상수
    • 상속을 위한 설계
    • Public 과 내부 인터페이스

▶︎ 개요

  • 파이썬 라이브러리의 네이밍 규칙은 다소 엉망이기 때문에 완벽한 일관성은 어렵다.
  • 그럼에도 현재 권장되는 네이밍 표준이 있다.
  • 새 모듈 및 패키지 (타사 프레임워크 포함) 는 이러한 표준에 따라 작성되어야 하지만 기존 라이브러리의 스타일이 다른 경우 내부 일관성이 선호된다.

▶︎ 가장 중요한 원칙

API 의 Public 파트로써 유저에게 보여지는 이름은
실행 (implementation) 이 아닌 사용법을 반영하는 작성규칙을 따라야 한다.


▶︎ 표현 (Descriptive) : 네이밍 스타일

  • 다양한 네이밍 스타일이 있다. 용도와 상관없이 어떤 이름 지정 스타일이 사용되고 있는지 인식할 수 있으면 도움이 된다.
  • 아래의 네이밍 스타일은 일반적으로 널리 쓰이는 스타일이다.
    • b (single lowercase letter)
    • B (single uppercase letter)
    • lowercase
    • lower_case_with_underscores
    • UPPERCASE
    • UPPER_CASE_WITH_UNDERSCORES
    • CapitalizedWords (CapWords, CamelCase, StudlyCaps 로 알려져 있기도 하다.)
      • CapWord 에서 줄임말을 사용할 때, 줄임말의 글자는 모두 대문자로 사용한다.
      • 예를 들어 HttpServerError 보다는 HTTPServerError 가 더 낫다.
    • mixedCase (첫 문자가 소문자)
    • Capitalized_Words_With_Underscores (못생긴!)

 

  • 이외 고유한 짧은 접두사를 사용하여 그룹을 나타내는 스타일이 존재한다.
    • 이것은 파이썬에서는 많이 사용되지 않지만, 문서의 완성도를 위해 언급한다.
    • 예를들어, os.stat() 기능은 st_mode, st_size, st_mtime 과 같이 전통적인 이름을 가진 튜플을 반환한다.
    • X11 라이브러리는 모든 이것의 public 함수에 대해 앞에 X 를 사용한다.
      • 파이썬에서 오브젝트가 속성과 메서드 이름에 접두어로 붙고, 함수 이름에 모듈 이름이 접두어로 붙기 때문에 이 스타일은 일반적으로 필요하지 않다고 여겨진다.
    • 추가적으로 앞 혹은 뒤에 _언더스코어를 사용한 아래의 특수 형태가 된다.
      (일반적으로 어느 작성규칙에도 조합 가능하다.)
      • _single_leading_underscore
        • 약한 “내부 사용" 표시기. 예를 들어 이름이 밑줄로 시작하는 객체는 가져오지 않는다. (from M import *)
      • single_trailing_underscore
        • Python 키워드와의 충돌을 피하기 위해 규칙에 따라 사용된다.
        • [ex] tkinter.Toplevel(master, class_=’ClassName’)
      • __double_leading_underscore
        • 클래스 속성의 이름을 지정할 때 네임 맹글링을 호출한다.
      • __double_leading_and_trailing_underscore__
        • 사용자가 제어하는 네임스페이스에 있는 “마법의" 개체 또는 속성이다.
        • 예 init__import__ 또는 __file__.
        • 그런 이름을 만들지 마라. 문서화된 대로만 사용하라.


 

▶︎ 규정 (Prescriptive) : 네이밍 스타일


▷ 피해야할 이름

  • I (소문자 엘 or 숫자 1)
  • O (대문자 or 숫자 0)
  • I (대문자 아이 or 소문자 엘)
  • 몇몇 폰트에서는 이 글자들을 숫자 1 or 0 과 구분이 쉽지 않으므로 위는 한 글자 변수이름으로 사용하지 않도록 한다. 소문자 엘을 사용할 때는 L 을 대신해서 사용하도록 한다.

▷ 패키지와 모듈 이름

  • 모듈은 짧으며 모두 소문자인 이름을 가져야 한다.
  • 언더스코어는 가독성을 향상시킬 수 있을 경우에 모듈의 이름에 사용될 수 있다.
  • 파이썬 패키지의 이름 또한 짧으며 모두 소문자여야 하지만, 언더스코어는 사용될 수 없다.
  • C 혹은 C++ 로 씌여진 확장 모듈이 높은 레벨 (더욱 객체지향적인) 인터페이스를 제공하는 파이썬 모듈을 가질 때, C/C++ 모듈은 이름 앞에 언더스코어가 있어야 한다. (ex. _socket)

▷ 클래스 이름

  • 클래스의 이름은 CapWords 작성규칙을 사용한다.
  • 함수에 대한 이름 작성 규칙은 인터페이스가 문서화되고 주로 호출이 가능하게 사용되어질 경우 대신 사용된다.
  • 내장 이름에 대한 별도의 작성 규칙이 있다.
    • 대부분의 내장 이름은 하나의 단어 (혹은 두 단어가 함께 실행됨) 이다.
    • 보통 예외이름 (Exception name) 과 내장 상수에 사용되고 CapWords 작성규칙이 사용된다.

▷ 타입 변수 이름

  • PEP 484 에 소개된 타입 변수의 이름은 짧은 이름을 선호하는 CapWords 방식을 사용한다.
  • T, AnyStr, Num 과 같이 공변 (covariant) 하거나 반변 (contravariant) 하는 거동을 선언하기 위해 사용되는 변수들에 대해서는 접미사 _co 혹은 _contra 가 붙여지는 것이 권장된다.
from typing import TypeVar

VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)

▷ 예외 이름 (Exception Names)

  • 예외는 클래스어야 하기 때문에 클래스 이름 작성규칙은 여기에도 적용한다.
  • 그러나 Error 접미사를 예외 이름에 사용되게 한다. (예외가 에러일 경우)

▷ 전역 변수 이름

  • 이 변수들은 하나의 모듈 안에서만 사용되는 것이 권장된다.
  • 작성규칙은 함수에 대한 작성 규칙과 거의 비슷하다.
  • from M import * 을 이용하여 사용되게 설계한 모듈은 전역 변수들을 exporting 하기 위해 __all__ 매커니즘을 사용하여야 하며 혹은 언더 스코어를 위의 전역변수 앞에 접두사로 붙이는 구식의 작성 규칙을 사용해야 한다.

▷ 함수 및 변수 이

  • 함수 이름은 가독성을 개선시켜야하므로, 언더 스코어로 구분된 소문자 단어로 구성된다.
  • 변수 이름은 함수 이름과 같은 작성 규칙을 따른다.
  • mixedCase 는 오로지 이전버전의 호환성을 유지할 필요가 있을 경우만 허락된다.

▷ 함수와 메서드의 독립변수

  • 항상 인스턴트 메서드에 대한 첫 번째 독립변수에는 self 를 사용한다.
  • 항상 클래스 매서드에 대한 첫번째 독립변수에는 cls 를 사용한다.
  • 만약 함수 독립 변수의 이름이 사용된 키워드와 충돌한다면, 축양형 혹은 철자를 바꾸는 것보다 하나의 언더스코어를 끝에 덧붙이는 것이 일반적으로 더 좋게 만든다.
    • class_ 가 clss 보다 낫다. (더 나은 것은 동의어를 사용하여 충돌을 피하는 것이다.)

▷ 메서드 이름 그리고 인스턴스 변수

  • 함수 네이밍 규칙을 사용하도록 한다.
    • 가독성 개선을 위해 언더스코어로 구분된 소문자 단어들을 사용한다.
  • Non-public 메서드와 인스턴스 변수에 대해서만 앞에 언더스코어를 사용한다.
  • 서브클래스를 사용할 때 이름 충돌을 피하기 위해, 파이썬의 맹글링 규칙에 따라 변수 앞에 2개의 언더스코어를 사용한다.
  • 파이썬은 클래스 이름과 함께 그 이름들을 심하게 훼손한다.
    • 만약 클래스 Foo 가 __a 로 명명된 속성을 가진다면 이것은 Foo.__a 로 접근할 수 없다.
    • 고집스러운 유저라면 Foo._Foo__a 를 호출함으로써 접근할 수 있다.
  • 일반적으로 변수 앞 두개의 언더스코어는 서브 클래스로 설계된 클래스에서 속성에 대해 이름 충돌을 피하기 위해 사용된다.

>>> 네임 맹글링 ?? (자세히보기)

더보기
💡 네임 맹글링 (name mangling) 이란? 링크
  • mangle : 짓이기다
  • 어원에서 유추할 수 있듯이 파이썬이 변수/함수의 이름을 짓이겨서 다른 이름으로 바꿔버리는 것을 말한다.
  • 맹글링을 적용하고 싶은 변수/함수명 앞에 언더바(_)를 2개 붙여서 적용할 수 있다.

>>> 파이썬에서 _ (언더바) 의 역할 (자세히보기)

더보기
💡 파이썬에서 _ (언더바) 의 역할 링크
  • Snake case 로 네이밍을 할 때 사용되는 것 외에도 다양한 사용처가 있다.
  • 크게 4가지로 분류

[1] 인터프린터에서의 마지막 값

[2] 무시하는 값

  • 튜플 등을 언패킹 할 때 특정 값을 버리는 용도로 언더바를 사용할 수 있다.
  • *(Asterisk) 를 이용하여 여러 개의 값을 무시할 수도 있다.
n_tuple = (1, 2, 3, 4, 5)
a, *_, b = n_tuple  # 2,3,4를 무시하고 1과 5만 언패킹

[3] 숫자 리터럴의 자릿수를 구분하는 역할

# 모두 숫자 100000000 을 의미한다.
number = 100_000_000
number_2 = 0x_5f_5e_100

[4] 네이밍 (4가지 경우로 분류 가능)

  • 언더바가 앞에 하나만 붙은 경우
    • 모듈 내에서만 해당 변수/함수를 사용하겠다는 의미 (=private)
    • 특히 협업을 할 때 다른 팀원에게 ‘이 변수/함수는 이 모듈 내부에서만 사용할 거다' 라고 명시적으로 힌트를 줄 수 있다.
    • 완전한 의미의 private 은 아니기 때문에 여전히 접근, 사용할 수 있다.
      • 파이썬은 private, public 의 확실한 구분이 없다.
    • 외부 모듈에서 해당 모듈을 from module_name import * 식으로 전체 임포트 할 때 앞에 언더바가 붙은 변수/함수는 임포트 하지 않는다.
  • 뒤에 언더바가 하나만 붙은 경우
    • 이 경우는 파이썬 키워드와 변수/함수명의 충돌을 피하기 위해 사용하는 경우
def print_(args):
	print('hi')

print_(list_)
  • 앞에 언더바가 두 개 붙은 경우
    • 네임 맹글링을 위한 경우
    • 맹글링 당한 변수/함수는 본연의 이름으로 접근할 수 없게 된다.
    • 네이밍 룰이라기 보다는 문법적인 요소.
    • ‘_클래스명__변수/함수명’ 형태로 이름이 변경된다.
  • 앞/뒤로 언더바가 2개씩 붙은 경우
    • 파이썬이 특별히 정의한 변수나 함수에 사용되는 네이밍 룰.
    • 대부분 오버라이딩 할 때 사용하게 된다.
    • 해당 네이밍 룰이 적용된 함수는 매직 메소드 (Magic Method), 던더 메소드 (Dunder Method, Double Underscore Method) 라고 부른다.

>>> 네임 맹글링을 사용하는 이유 (자세히보기)

더보기
💡 크게 2가지 상황에서 네임 맹글링을 사용할 수 있다.
  • 클래스 속성값을 외부에서 접근하기 힘들게 할 때 (private 화)
    • 맹글링을 적용한 속성은 ‘_클래스명_속성명' 의 형태로 이름이 바뀐다.
    • 즉, 외부 접근을 어렵게 할 뿐 완벽하게 보호해주는 것이 아니기에 완벽한 private 기능은 아니다.
  • 하위 클래스가 상위 클래스의 속성을 오버라이딩 하는 것을 막을 때
    • 클래스가 확장되면서 크기가 커지면 속성 이름간의 충돌이 발생할 수 있다.
    • 이런 점에서 맹글링을 적용시킬 수 있다. (특히 오버라이딩을 막고자 할 때)

▷ 상수

  • 상수는 모듈 레벨에서 정의되고, 언더스코어로 구분되어 대문자로 작성된다.
    • MAX_OVERFLOW, TOTAL

▷ 상속을 위한 설계

  • 항상 클래스의 메서드와 인스턴스 변수가 public 이 되는지 non-public 이 되는지 결정하도록 한다.
    • 만약 확신하지 못한다면 non-public 로 결정하는 것이 좋다.
      • public → non-public 보다 non-public → public 속성으로 만드는 것이 더 쉽다.
  • Public 속성은 사용을 위한 클래스의 관련없는 클라이언트가 사용할 것으로 예상되는 속성이다.
    • 이전 버전과 호환되지 않는 변경 사항을 피하도록 노력하라.
  • Non-public 속성은 서드파티에 의해 사용되지 않는 것이다.
    • 해당 속성은 바뀌지 않거나 제거되지 않는다는 것이 보장되지 않는다.
  • 파이썬에는 ‘private’ 속성이 없기 때문에, 해당 용어를 사용하지 않겠다.
  • 속성의 또 다른 카테고리는 서브클래스 API 부분이다. (종종 ‘protected’ 라고 다른 언어에서 불림)
    • 몇몇 클래스는 클래스 기능의 수정과 확장을 위해 상속을 염두해두고 설계된다.
    • 이러한 클래스를 디자인할 때는 어떤 속성이 public 인지, 서브클래스 API 의 일부인지, 기본 클래스에서만 사용해야 하는지 명시적으로 결정해야 한다.

 

  • 이에 대한 Pythonic 지침
    • Public 속성은 이름앞에 ‘_’ (언더스코어) 를 가지지 않는다.
    • 만약 public 속성 이름이 예약된 키워드와 충돌한다면, 이름 뒤에 하나의 언더스코어(_) 를 붙이도록 한다. 이것은 축약형이나 스펠링을 파괴하는 것보다 선호되는 방법이다.
      • 단, 이 규칙에도 불구하고 ‘cls’ 는 클래스로 알려진 모든 변수나 인수, 특히 클래스 메서드의 첫 번째 인수에 대해 선호되는 철자이다.
    • 단순한 공개 데이터 속성의 경우 복잡한 접근자/변이자 메서드 없이 속성 이름만 노출하는 것이 가장 좋다.
    • 만약 단순한 데이터 속성이 기능적으로 향상되는 것을 필요로 할 때, 파이썬은 향후 향상을 위한 쉬운 경로를 제공한다는 점을 명심하라. 이 경우 속성을 사용하여 간단한 데이터 속성 액세스 구문 뒤에 기능 구현을 숨긴다.
      • 참고 1: 캐싱과 같은 부작용은 일반적으로 괜찮지만 기능적 동작 부작용이 없도록 유지하라.
      • 참고 2: 계산 비용이 많이 드는 작업에는 속성을 사용하지 마라. 속성 표기법은 호출자가 액세스가 (상대적으로) 저렴하다고 믿게 만든다.
    • 만약 클래스가 서브 클래스화 되는 것이 고려될 때, 서브클래스에서 사용하길 원하지 않는 속성을 가지고 있다면, 이름 앞에 2개의 언더스코어를 활용하는 네이밍 (맹글링) 을 사용하라.
      • 참고 1: 단순한 클래스명은 맹글링된 이름에서 사용된다는 것을 참고하라. 만약 서브클래스가 같은 클래스 이름과 같은 속성 이름을 선택한다면, 여전히 이름 충돌을 가질 수 있다.
      • 참고 2: 이름 맹글링은 디버깅과 같은 특정 용도 getattr() 을 덜 편리하게 만들 수 있다. 그러나 이름 맹글링 알고리즘은 잘 문서화되어 있으며 수동으로 수행하기 쉽다.
      • 참고 3: 모든 사람이 이름 맹글링을 좋아하는 것은 아니다. 실수로 이름이 충돌하지 않도록 해야 하는 필요성과 고급 발신자가 사용할 수 있는 가능성 사이에서 균형을 유지하라.

Public 과 내부 인터페이스

  • 이전 버전과의 호환성 보장은 오직 public 인터페이스에게만 적용한다.
    • 그런 이유로, 유저들이 명확히 public 과 내부 인터페이스 간의 구분할 수 있게 하는 건 매우 중요하다.
  • 문서화된 인터페이스는 public 을 고려한다. 문서화되지 않은 모든 인터페이스는 내부로 간주되어야 한다.
  • Introspection 을 더 잘 지원하기 위해 모듈은 all 속성을 사용하여 public API 내부에서 이름을 명시적으로 선언해야 한다.
    • __all__ 을 빈 목록으로 설정하면 모듈에 public API 가 없음을 나타낸다.
  • __all__ 을 적당하게 사용해 내부 인터페이스 (패키지, 모듈, 클래스, 함수, 속성 혹은 다른 이름들) 은 하나의 언더스코어를 사용하여 접두어를 붙여야 한다.
  • 만약 어느 네임스페이스가 내부로 고려된다면, 어느 인터페이스도 내부로 고려된다.
  • Import 된 이름들은 항상 세부 구분사항으로 고려되어야 한다.
    • 다른 모듈은 하위 모듈의 기능을 노출하는 os.path 혹은 패키지의 init 모듈과 같이 명시적으로 보유하고 있는 모듈의 API 에 대해, 문서화된 부분이 아니라면, import 된 이름에 대한 간접적인 접근에 의존해서는 안된다.

>>> __all__ ?? (자세히보기)

더보기
  • 특정 디렉터리의 모듈을 * 를 이용하여 import 할 때에는 해당 디렉터리의 init.py 파일에 all 이라는 변수를 설정하고 import 할 수 있는 모듈을 정의해 주어야 한다.
    • __all__ 로 정의하지 않으면 인식되지 않는다.
form travel import *
  • * 는 해당 패키지에 있는 모든 것을 가져다 사용하겠다는 것인데, 실제로는 패키지를 만든 사람이 공개 범위를 설정할 수 있다.
  • __all__ 이라는 변수에 리스트 형태로 공개하려는 모듈 이름을 추가하면 해당 모듈에 대해 공개 설정을 할 수 있게 된다.

대표이미지용