# 작명 컨벤션
Python 라이브러리의 작명 컨벤션은 좀 망쳐져 있다. 그래서 앞으로도 절대 일관성 있게 유지할 수가 없다. 그럼에도 불구하고 권장하는 작명 기준을 소개한다. 새로운 모듈들과 패키지들(서드 파티 프레임워크 등을 포함하여)은 이 기준대로 작성해야 한다. 하지만 이미 존재하는 라이브러리에서 다른 스타일을 따르고 있다면 내부의 일관성을 우선하자.(역: 그 라이브러리의 스타일을 우선하자)
# 오버라이딩 원리
API의 공개 부분으로 사용자에게 표시되는 이름은 구현보다는 사용법을 반영하는 컨벤션을 따르자.
# 설명: 작명 스타일
다양한 작명 스타일이 존재한다. 이는 작명 스타일의 용도와는 별개로 어떤 작명 스타일이 사용되는지 깨닫게 도와준다.
일반적으로 다음과 같이 분류한다.
b
(단일 소문자)B
(단일 대문자)lowercase
(역: 소문자)lower_case_with_underscores
(역: 밑줄로 구분된 소문자)UPPERCASE
(역: 대문자)UPPER_CASE_WITH_UNDERSCORES
(역: 밑줄로 구분된 대문자)CapitalizedWords
(또는 CapWords[1], CamelCase 라고 불리운다. 글자의 울퉁불퉁한 모양 때문에 그렇게 이름이 붙여졌다.[2]) 이는 StudlyCaps로 라고도 불리운다.
참고
CapWords 스타일로 약어를 사용할 때, 약어의 모든 문자를 대문자로 사용하자. 예를 들면, HTTPServerError
가 HttpServerError
보다 좋다.
mixedCase
(단어 첫 글자가 소문자로 CapitalizedWords와는 다르다!)Capitalized_Words_With_Underscores
(못생겼다!)
짧은 고유 접두어를 사용하여 관련 이름을 함께 그룹화하는 스타일도 있다.
파이썬에서는 많이 쓰이진 않지만, 글의 완성도를 위해 언급한다. 예를 들어, os.stat()
함수는 전통적으로 st_mode
, st_size
, st_mtime
등과 같은 이름을 가진 튜플을 반환한다.
(POSIX 시스템 호출 구조의 필드와의 관련성을 강조하여 이에 익숙한 프로그래머들을 돕는다.)
X11 라이브러리는 모든 퍼블릭 함수에 첫글자 X를 사용한다. Python에서 이 스타일은 일반적으로 불필요하다고 간주된다. 왜냐하면 Python에서는 어트리뷰트명과 메소드명은 오브젝트명으로 접두어를 붙이고, 함수명은 모듈명으로 접두어를 붙이기 때문이다.
덧붙여, 다음과 같이 선행 또는 후행 밑줄을 사용하는 특수 형식이 알려져있다. (일반적으로 모든 경우의 컨벤션과 결합 될 수 있다.)
_single_leading_underscore
: 약한 "내부 사용" 지표(indicator). 예시로,from M import *
는 이름이 밑줄로 시작하는 개체는 가져오지 않는다.single_trailing_underscore_
: 파이썬 키워드와의 충돌을 피하기 위해 관례로 사용한다. 예시로,
tkinter.Toplevel(master, class_='ClassName')
__double_leading_underscore
: 클래스 어트리뷰트의 이름을 지정할 때, 네임 맹글링을 호출한다.
(class FooBar 내부의__boo
는_FooBar__boo
가 된다. 아래 섹션의 내용 참조)__double_leading_and_trailing_underscore__
: 사용자 제어 네임스페이스에 있는 "매직" 객체(magic object) 또는 어트리뷰트(magic attribute). 예시로,__init__
,__import__
or__file__
, 이런 스타일의 이름은 문서에 명시된 것만 사용하자.
# 규정: 작명 컨벤션
# 피해야할 이름
l
(소문자 엘), O
(대문자 오), I
(대문자 아이)는 단독으로 변수명으로 절대 사용하지 마라.
몇몇 폰트에서는 이 글자들이 숫자 1, 0과 구분하기 어렵다. l
을 쓰고 싶을 땐 L
을 쓰자.
# ASCII 호환성
표준 라이브러리에서 사용되는 식별자들은 반드시 ASCII 호환성을 따라야한다. PEP 3131open in new window의 정책 섹션open in new window 에 설명된 것처럼 말이다.
# 패키지명과 모듈명
모듈명은 모두 소문자를 사용하여 짧게 지어야한다. 밑줄(Underscores)은 가독성 향상을 위해 사용될 수 있다.
패키지명은 또한 모두 소문자를 사용하여 짧게 지어야한다. 단, 밑줄은 권장되지 않는다.
C 또는 C++ 로 쓰여진 확장모듈들이 더 높은 레벨의 인터페이스를 제공하는 Python 모듈(예를 들면, 더 객체 지향적인)을 동반할 경우, C/C++ 모듈들은 첫글자 밑줄 이름으로 짓는다. (예를 들면 _socket
)
# 클래스명
클래스명들은 일반적으로 CapWords 컨벤션을 따른다.
인터페이스가 문서화되어 있고, 주로 Callable[3]로 사용되는 경우에도, 함수의 작명 컨벤션을 따를 수 있다.
내장 된 클래스들과 컨벤션이 다른 것에 주목하자. 대부분의 내장 된 클래스명은 단일 단어(또는 두 개의 단어가 결합된 혼성어)다. CapWords 컨벤션은 예외(exception)명이나 내장 상수에만 사용된다.
# 타입 변수명
PEP484open in new window 에서 소개된 타입 변수의 이름은 CapWords 를 사용하여 짧게 짓는다. 예를들어, T
, AnyStr
, Num
과 같은 경우가 해당된다._co
나 _contra
접두어를 공변(covariant)과 반변(contravariant)[4] 행위를 선언하기 위해 사용할 수 있다. 다음처럼 말이다.
from typing import TypeVar
VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)
2
3
4
# 예외명
예외는 클래스기 때문에, 클래스 작명 컨벤션을 적용한다. 하지만 만약 예외가 실제로 오류일 경우(역: 오류와 같은 개념일 경우), "Error"
라는 접두어를 예외명 앞에다 붙여야한다.
# 전역 변수명
(이 변수들이 하나의 모듈 안에서만 있다고 가정하자)
이 경우 작명 컨벤션은 함수에 대한 컨벤션과 같다.
from M import *
를 사용하기 위해 설계된 모듈들은 __all__
메커니즘을 사용해야 한다. 그럼으로써 전역변수 내보내기를 하는 것을 막아야 한다.
또는 밑줄을 접두어로 넣는 오래된 컨벤션을 사용하자. (이 전역 변수들이 "module non-public"[5]임을 나타내고 싶을 수 있을 때)
# 함수와 변수명
함수명은 소문자여야하며 가독성 향상을 위해 밑줄로 단어를 구분해야한다.
변수명도 함수명과 같은 컨벤션을 따른다.
mixedCase 는 이미 스타일이 존재하는 컨텍스트(예를 들면, threading.py
)에만 허용된다. 이는 하위 호환성을 지키기위한 것이다.
# 함수와 메소드의 아규먼트들
항상 self
를 인스턴스 메소드의 첫번째 아규먼트로 사용한다.
항상 cls
를 클래스 메소드의 첫번째 아규먼트로 사용한다.
만약 함수의 아규먼트명이 이미 있는 키워드와 충돌이 있을 경우, 일반적으로 후행 밑줄을 추가하는 것이 약어 또는 철자 손상을 사용하는 것보다 낫다. 따라서 class_
가 clss
보다 낫다. (혹은 동의어등을 사용하여 이러한 충돌을 피하는 것이 더 나을 수 있다.)
# 메소드명과 인스턴스 변수
함수 작명 규칙처럼, 소문자를 사용하고 가독성 향상을 위해 밑줄로 단어를 구분하자.
첫글자만 밑줄인 단어는 non-public 인 메소드와 인스턴스 변수들을 위해서만 쓰여야 한다.
하위 클래스들과의 이름 충돌을 피하기위해, 두 개의 밑줄로 시작하는 단어를 사용하여 Python의 이름 맹글링[6] 규칙을 불러오자(invoke).
Python 은 다음과 같이 이름들을 클래스명과 함께 맹글한다. 만약 클래스 Foo
가 __a
어트리뷰트를 갖고 있을 경우, Foo.__a
로 접근할 수 없다. (필요한 사용자는 Foo._Foo__a
를 호출하여 여전히 접근할 수는 있다.) 일반적으로 두 개의 밑줄만으로 시작하는 이름은 하위 클래스로 설계된 클래스 내의 어트리뷰트와 이름 충돌을 피하는 용도로 사용된다.
안내
__names
를 사용하는 것에 대해 논쟁이 있다. (아래를 참고하기).
# 상수
상수는 주로 모듈 레벨에서 정의된다. 그리고 대문자로만 쓰여지며 밑줄로 단어를 구분한다. 예를 들면, MAX_OVERFLOW
와 TOTAL
.
# 상속을 고려한 설계
항상 클래스 메소드와 인스턴스 변수(통칭: "어트리뷰트")가 퍼블릭인지 아닌지 결정하라. 만약 결정되지 않았다면, 퍼블릭이 아닌 컨벤션을 골라라. 나중에 퍼블릭으로 바꾸는 것이 퍼블릭을 아닌 것으로 바꾸는 거보다 더 쉽다.
퍼블릭 어트리뷰트는 하위 호환성을 유지하려는 노력과 함께, 당신이 만든 클래스와 관련없는 클라이언트가 사용할 예정인 어트리뷰트다. 퍼블릭이 아닌 어트리뷰트는 외부에서 사용되게끔 의도하지 않는 어트리뷰트다. 그래서 퍼블릭이 아닌 어트리뷰트가 앞으로 바뀌거나 제거되지 않을 것이라는 보장을 하지 말아야된다.
우리는 "프라이빗(private)"이라는 용어를 사용하지 않는다. 왜냐하면 어떠한 어트리뷰트도 실제 Python 에서는 프라이빗일 수 없기 때문이다. (일반적으로 불필요한 양의 추가 작업 없이는 실제 프라이빗으로 만들 수 없다.)
어트리뷰트들의 다른 종류로는 "하위클래스 API"의 일부인 어트리뷰트가 있다. (다른 언어에서 자주 "protected"로 표현되는 어트리뷰트) 몇 클래스는 클래스의 행위의 측면에서 확장 또는 수정(modify)하기 위해 상속 받도록 설계되었다. 그러한 클래스를 설계할 때는, 어떤 어트리뷰트를 퍼블릭으로 하고, 어떤 부분을 하위클래스 API로 할 것이며, 그리고 어떤 어트리뷰트를 진짜로 당신의 기반 클래스에서만 사용할 것인지 명시적인 결정을 하는 것에 주의해야한다.
이를 명심하며, 다음의 Python스러운 가이드라인을 살펴보자.
퍼블릭 어트리뷰트는 첫 글자가 밑줄이면 안 된다.
만약 퍼블릭 어트리뷰트명이 이미 있던 키워드와 충돌하면, 하나의 후행 밑줄을 어트리뷰트명에 추가하자. 이는 약어나 철자 손상보다 권장된다. (하지만 예외도 있다.
'cls'
는 클래스를 나타내는 변수 또는 아규먼트로, 특히 클래스 메소드의 첫번째 아규먼트로도 바람직한 철자다.)
안내 1
위에 안내 된 클래스 메소드에서의 아규먼트 권장사항을 참고
- 간단한 퍼블릭 데이터 어트리뷰트를 위해선 단순히 어트리뷰트명을 복잡한 접근자, 설정자(mutator) 없이 노출하는 것이 가장 좋다. Python 은 단순한 데이터 어트리뷰트가 기능적 행위(functional behavior)을 확장해야하는 경우, 향후 향상(enhancement)을 위한 쉬운 길을 제공하고 있다는 것을 명심하자. 이러한 경우, 프로퍼티를 사용하여 간단한 데이터 어트리뷰트 접근 구문 뒤에 기능 구현을 숨기자.
안내 1
프로퍼티는 새로운 스타일의 클래스에서만 작동한다.
안내 2
기능적 행위의 사이드 이펙트(side-effect)가 없도록 유지하도록 노력하자. 하지만 캐싱과 같은 사이드 이펙트는 일반적으로 괜찮다.
안내 3
계산적으로 비용이 높은 연산에 프로퍼티를 사용하는 것을 피하자. 어트리뷰트 표기법이 호출자(caller)의 접근 비용이 (상대적으로) 낮음을 보장한다.
- 하위 클래스로 의도된 클래스일 경우, 그리고 하위 클래스에서 사용하지 않으려는 어트리뷰트가 있는 경우 두개의 밑줄로 시작하여 후행 밑줄이 없는 작명법을 고려하자. 이는 Python 의 이름 맹글링 알고리즘을 불러일으킨다. 해당 어트리뷰트가 있는 클래스의 이름 또한 어트리뷰트명으로 맹글된다. 이는 하위클래스에 예기치 않게 같은 이름의 어트리뷰트가 포함된 경우 어트리뷰트명 충돌을 방지하는데 도움이 된다.
안내 1
단순한 클래스(역: 여기서는 상속하지 않은 클래스)의 이름만이 맹글된 이름에 사용되는 것을 주목하자. 그렇기 때문에 만약 하위 클래스가 같은 클래스명과 어트리뷰트명을 선택할 경우, 여전히 이름 충돌을 겪을 것이다.
안내 2
이름 맹글링은 디버깅이나 __gertattr__()
같은 특정 용도를 더 불편하게 만들 수 있다. 하지만 이름 맹글링 알고리즘은 잘 문서화 되어있으며, 메뉴얼하게 수행하기 쉽다.
안내 3
모두가 이름 맹글링을 좋아하는 것은 아니다.
우발적인 이름 충돌을 방지하는 것과 고급 호출자(역: 여기서는 mangling 관련)의 잠재적인 사용 간 균형을 맞추자.
# 퍼블릭 그리고 내부 인터페이스
하위 호환성은 퍼블릭 인터페이스만 보장한다. 따라서, 사용자가 퍼블릭 인터페이스와 내부 인터페이스를 분명하게 구분할 수 있도록 하는 것이 중요하다.
문서화된 인터페이스는 퍼블릭으로 간주된다. 문서에서 일반적으로 하위 호환성 보장에서 제외되는 임시(provisional) 또는 내부 인터페이스라고 명시적으로 선언하지 않는 한 말이다. 모든 문서화되지 않은 인터페이스는 내부 인터페이스 간주된다.
더 나은 검사(introspection) 지원을 위해선, 모듈은 퍼블릭 API 에서 __all__
어트리뷰트를 사용함으로써 이름을 명시적으로 선언해야한다. __all__
을 빈 리스트로 설정하는 것은 모듈이 퍼블릭 API 가 없음을 나타낸다.
__all__
이 적절히 설정되었음에도 내부 인터페이스 (패키지, 모듈, 클래스, 함수, 어트리뷰트나 다른 이름들)은 첫글자만 밑줄인 단어를 사용해야한다.
인터페이스를 갖고 있는 네임스페이스(패키지, 모듈, 또는 클래스)가 내부(internal)로 간주될 경우 또한 내부 인터페이스로 간주된다.
가져오기 된 이름은 구현 세부사항으로 항상 간주되어야 한다. 이를 포함하는 모듈의 API의 명시적으로 문서화 된 부분이 아닌 한, 다른 모듈들은 가져오기 된 이름으로의 간접적인 접근에 의존하지 않아야한다. 예를 들면 os.path
나 패키지의 __init__
모듈 같이 하위 모듈로부터 기능이 노출된 API 말이다.
역: 첫 글자 대문자. 예:
MyClass
↩︎http://www.wikipedia.com/wiki/CamelCaseopen in new window 역: 여기서는 첫글자가 대문자인 UpperCamelCase 만을 말한다. ↩︎
호출할 수 있는. 예:
my_class()
↩︎모듈을 기준으로 public 이 아닌 것 ↩︎