좋은 코딩 스타일은 올바른 문장 부호와 같습니다: 없어도 어떻게든 살아갈 수는 있겠지만,있어야읽기가훨씬수월합니다. 아주 초보 프로그래머일지라도 코드 스타일에 신경을 쓰는 것이 좋습니다. 일관된 스타일을 사용하면 다른 사람들(미래의 본인을 포함하여!)이 여러분의 작업물을 더 읽기 쉬워지며, 특히 다른 사람의 도움을 받아야 할 때 매우 중요합니다.
처음에는 코드 스타일을 맞추는 것이 다소 번거롭게 느껴질 수 있지만, 연습하다 보면 곧 제2의 천성처럼 자연스러워질 것입니다. 또한 Black 파이썬 패키지(“원하는 어떤 색상이든 가질 수 있습니다, 그것이 검은색인 한”)와 같이 기존 코드를 빠르게 다시 스타일링해 주는 훌륭한 도구들도 있습니다.
pixi global install black을 실행하여 Black을 설치하면, Visual Studio Code 내의 명령줄(터미널)에서 이를 사용할 수 있습니다. 터미널을 열고(Terminal -> New Terminal) black *.py를 실행하여 현재 디렉토리의 모든 파이썬 스크립트에 표준 코드 스타일을 적용해 보세요.
이름 짓기 (Names)
첫째, 이름이 중요합니다. 변수, 함수 등 이름을 짓는 대상이 무엇이든 의미 있는 이름을 사용하세요. 지금은 이해하더라도 나중에 다른 사람이나 미래의 본인이 보기에 불명확할 수 있는 약어는 피하세요. 예를 들어 re_wg_ph 보다는 real_wage_hourly를 사용하세요. temp라고 짓고 싶은 유혹이 크겠지만, 나중에 temp가 무엇을 하는지 혹은 무엇이었는지 도저히 기억나지 않을 때 후회하게 될 것입니다. 불리언(참 또는 거짓인 변수) 이름을 지을 때 좋은 요령은 is 뒤에 해당 불리언 변수가 참조하는 내용을 붙이는 것입니다. 예: is_married.
이러한 일반적인 팁 외에도, 파이썬에는 다양한 종류의 변수 명명 규칙이 있습니다. 거의 모든 객체에 대한 명명 규칙은 언더스코어로 구분된 소문자입니다. 예: a_variable=10 또는 ‘this_is_a_script.py’. 이러한 명명 스타일을 스네이크 케이스(snake case)라고도 합니다. 하지만 다른 명명 규칙들도 존재합니다. Allison Horst는 현재 사용되는 다양한 규칙들을 보여주는 환상적인 만화를 만들었습니다.
스네이크 케이스 규칙에는 세 가지 예외가 있습니다: 클래스는 카멜 케이스(camel case)여야 합니다(예: ThisIsAClass). 상수는 대문자 스네이크 케이스여야 합니다(예: THIS_IS_A_CONSTANT). 그리고 패키지는 대개 공백이나 언더스코어 없이 소문자로만 구성됩니다(thisisapackage).
pandas 데이터 프레임의 열이나 다른 문자열 변수의 이름을 빠르게 바꾸고 싶다면, 유니코드를 지원하는 slugify 라이브러리나 dataprep 라이브러리의 clean_headers() 함수를 사용해 보세요.
변수 이름을 더 잘 지을수록 코드는 더 명확해질 것이며, 주석을 더 적게 써도 될 것입니다!
요약하자면: - 여러분의 의도를 드러내는 묘사적인 변수 이름을 사용하세요. 예: days_since_treatment - 이름에 모호한 약어 사용을 피하세요. 예: rw_ph 대신 real_wage_hourly 사용 - 항상 동일한 어휘를 사용하세요. 예: worker_type에서 갑자기 employee_type으로 바꾸지 마세요 - 핵심 파라미터를 설정하는 코드 내의 숫자인 ’매직 넘버(magic numbers)’를 피하세요. 대신 이를 이름이 있는 상수로 설정하세요. 예시: ```python import random
# 좋지 않은 예
def roll():
return random.randint(0, 36) # 매직 넘버!
# 좋은 예
MAX_INT_VALUE = 36
def roll():
return random.randint(0, MAX_INT_VALUE)
- 함수 이름에는 동사를 사용하세요. 예: `get_regression()`
- 함수 이름에 일관된 동사를 사용하세요. `get_score()`와 `grab_results()`를 섞어 쓰지 마세요(둘 다 `get`을 사용하세요)
- 변수 이름은 snake_case이고 모두 소문자여야 합니다. 예: `first_name`
- 클래스 이름은 CamelCase여야 합니다. 예: `MyClass`
- 함수 이름은 snake_case이고 모두 소문자여야 합니다. 예: `quick_sort()`
- 상수는 snake_case이고 모두 대문자여야 합니다. 예: `PI = 3.14159`
- 모듈은 짧고 snake_case인 소문자 이름이어야 합니다. 예: `pandas`
- 작은따옴표와 큰따옴표는 동일하므로 하나를 선택하여 일관되게 사용하세요. 대부분의 자동 포맷터는 `"`를 선호합니다.
## 공백 (Whitespace)
코드 조각들을 공백으로 둘러싸면 가독성을 크게 높일 수 있습니다. 그러한 관례 중 하나는 함수 정의가 끝난 뒤 두 줄의 빈 줄을 두는 것입니다. 또 다른 하나는 할당문 사이를 공백으로 띄우는 것입니다.
```python
this_is_a_var = 5
또 다른 관례는 쉼표 , 뒤에 공백을 두는 것입니다. 예를 들어 리스트 정의 시 다음과 같이 합니다.
앞서 언급했듯이, 파이썬은 # 뒤의 모든 텍스트를 무시합니다. 이를 통해 파이썬은 무시하지만 다른 인간은 읽을 수 있는 텍스트인 주석을 작성할 수 있습니다. 주석은 뒤따르는 코드가 무엇을 하는지 간략하게 설명하는 데 도움이 될 수 있습니다. 함수나 변수 이름으로 전달되지 않는 추가적인 맥락 정보를 제공하기 위해 주석을 사용하세요.
사실, 잘 작성된 코드는 무슨 일이 일어나는지 더 명확하게 보여주기 때문에 주석이 더 적게 필요합니다. 그리고 코드가 변경되더라도 주석은 업데이트되지 않는 유혹에 빠지기 쉽습니다. 그러니 주석을 달되, 먼저 코드가 스스로 이야기를 하도록 만들 수 있는지 고민해 보세요.
또한 코드를 보기만 해도 이미 알 수 있는 내용을 말하는 “노이즈” 주석은 피하세요.
고양이가 cat이라고 쓰인 레이블을 목에 걸고 있는 사진
마지막으로, 함수에는 독스트링(doc string)이라고 불리는 특별한 유형의 주석이 있습니다. 여기에는 함수의 입력과 출력에 대한 모든 내용이 담겨 있으며, 입력과 출력의 타입(여기서는 데이터 프레임, 즉 pd.DataFrame)도 포함됩니다.
def round_dataframe(df: pd.DataFrame) -> pd.DataFrame:"""데이터 프레임의 수치형 열을 유효숫자 2자리로 반올림합니다. Args: df (pd.DataFrame): 입력 데이터 프레임 Returns: pd.DataFrame: 숫자들이 유효숫자 2자리로 반올림된 데이터 프레임 """for col in df.select_dtypes("number"): df[col] = df[col].apply(lambda x: float(f'{float(f"{x:.2g}"):g}'))return df
행 너비와 행 바꿈 (Line width and line continuation)
다소 임의적인 역사적 이유 때문에, PEP8은 각 코드 줄을 79자 이내로 할 것을 제안합니다. 어떤 사람들은 이것이 특히 와이드 모니터를 사용하는 시대에 너무 제한적이라고 생각합니다. 하지만 매우 긴 줄을 나누는 것은 좋습니다. 괄호 안에 포함된 내용은 다음과 같이 여러 줄로 나눌 수 있습니다:
def function(input_one, input_two, input_three, input_four): result = (input_one,+ input_two,+ input_three,+ input_four)return result
메서드 체이닝(method chaining)(데이터 변환 (Data Transformation) 에서 보실 수 있습니다)을 사용할 때는 체인을 괄호 안에 넣어야 하며, 매 메서드마다 새로운 줄을 사용하는 것이 좋은 습관입니다. 아래 코드 조각은 좋은 예시를 보여줍니다:
자동화가 스타일 적용을 도울 수는 있지만, 클린 코드(clean code) 작성을 도와주지는 못합니다. 클린 코드는 코드를 읽기 쉽고, 유지 관리 가능하며, 확장 가능하게 유지하도록 돕는 일련의 규칙과 원칙입니다. 코드를 작성하는 것은 쉽지만 클린 코드를 작성하는 것은 어렵습니다! 하지만 이 원칙들을 따른다면 큰 무리는 없을 것입니다.
반복하지 마라 (Do not repeat yourself, DRY)
DRY 원칙은 ’시스템 내에서 모든 지식 조각이나 로직은 단일하고 모호하지 않은 표현을 가져야 한다’는 것입니다. 코드를 재사용 가능한 조각으로 나누어 언제 어디서든 호출할 수 있게 하세요. 긴 메서드를 작성하지 말고 로직을 명확하게 구분된 덩어리로 나누세요.
이를 통해 코드를 반복하지 않아도 되고, 동일한 함수의 이 버전인지 저 버전인지 몰라 헤매는 일을 방지하며 디버깅 노력을 크게 줄여줄 것입니다.
실무에서 DRY를 적용하는 몇 가지 실질적인 방법은 함수를 사용하는 것, 여러 스크립트에서 반복적으로 실행해야 하는 함수나 코드를 다른 스크립트(예: utilities.py)에 넣고 이를 임포트하는 것, 그리고 코드를 더 간결하게(그러면서도 읽기 쉽게) 작성할 다른 방법이 있는지 신중히 생각하는 것입니다.
{.callout-note} 팁 :class: tip Visual Studio Code를 사용 중이라면, 코드를 우클릭하고 'Extract to method' 옵션을 사용하여 [코드를 함수로 자동 전송](https://code.visualstudio.com/docs/editor/refactoring)할 수 있습니다.
KISS (Keep It Simple, Stupid)
대부분의 시스템은 복잡하게 만들기보다는 단순하게 유지할 때 가장 잘 작동합니다. 이는 불필요한 복잡성을 피하라는 규칙입니다. 코드가 복잡하면 나중에 다시 돌아왔을 때 본인이 한 일을 이해하기가 더 어려워질 뿐입니다.
SoC (Separation of Concerns) / 모듈화하기
모든 것을 처리하는 단일 파일을 만들지 마세요. 코드를 분리되고 독립적인 모듈로 나누면 읽고, 디버그하고, 테스트하고, 사용하기가 더 쉬워집니다. 코딩 기초 장에서 다른 스크립트의 함수를 생성하고 임포트하는 방법을 확인할 수 있습니다. 하지만 스크립트 내에서도 입력과 출력이 명확한 함수를 정의함으로써 코드를 모듈화할 수 있습니다.
하나의 목적을 달성하는 코드가 약 30줄 이상 길어진다면 함수로 넣어야 한다는 것이 좋은 경험칙입니다. 500줄이 넘는 스크립트 또한 분할하기에 적당한 시점입니다.
이와 관련하여, 모든 일을 하려고 시도하는 단일 함수를 만들지 마세요. 함수 또한 한계가 있어야 하며, 대략적으로 한 가지 일만 수행해야 합니다. 함수 이름을 짓는데 ’and’를 써야 한다면 그 함수는 두 개로 나누는 것이 좋습니다.
함수는 ’부수 효과(side effects)’도 없어야 합니다. 즉, 값(들)을 입력받아 리턴 문을 통해 값(들)을 출력하기만 해야 합니다. 전역 변수를 수정하거나 다른 변경을 가해서는 안 됩니다.
또 다른 좋은 경험칙은 각 함수가 너무 많은 별도의 인수를 가지지 않아야 한다는 것입니다.
모듈화와 함수 생성을 위한 마지막 팁은 함수에 ‘플래그(flags)’(일명 불리언 조건)를 사용하지 않아야 한다는 것입니다. 예시입니다:
# 좋지 않은 예def transform(text, uppercase):if uppercase:return text.upper()else:return text.lower()# 좋은 예def uppercase(text):return text.upper()def lowercase(text):return text.lower()