본문 바로가기

Study/클린 코드, 이제는 파이썬이다

유지 보수와 Type-Safe한 쉬운 파이썬 코드 만들기 - 주석과 타입 힌트에 대하여


프로그래밍을 할 때, 기능을 추가하거나 고칠 때마다 필연적으로 코드 변경이 일어나기 마련이다. 이럴 때, 팀원이 코드를 이해해야 변경도 가능하므로 코드를 가독성 있게 유지하는 것이 중요하다.

또한 직접 작성한 코드도 시간이 지나면 잊어버리기 마련이다. 이 때, 주석은 프로그래머가 코드를 떠올리게 도와주고, 로직에 대한 메모나 경고 역할을 해준다.

오늘은 이처럼 프로그래밍 분야에서 중요한 '주석', '독스트링', '타입 힌트'에 대해 알아보겠다.

## 주석
```python
# 이것은 단일행 주석이다! 기호 '#'으로 사용한다.

"""이것은
다중행 문자열로 구성되어
다중행 주석으로 사용한다."""
```

파이썬은 단일행, 다중행 주석 모두 지원한다. 전문적이고 가독성 높은 코드를 작성하고 싶으면 주석은 필수로 작성해야 한다.

### 주석 스타일
좋은 주석 스타일을 몇 가지 살펴보자.

* 주석은 일반적으로 코드 행 끝보다는, 새로운 행에 존재해야 한다.
(이 경우, 대상 코드 위 줄에 삽입한다.)
* 구문이나 단어 하나보다는, 완전한 문장이여야 한다.
* 주석은 대상 코드와 동일한 수준으로 들여쓰기 해야 한다.
* 단일행 주석에서는 # 기호 뒤에 반드시 공백을 둬야 한다.
* 주석으로 링크 내용을 넣지 말아야 한다.

### 인라인 주석
인라인 주석은 코드 행 끝에 넣는 주석을 말한다.
```python
while True: # 플레이어가 유효한 이동 명령을 입력할 때까지 계속 질문한다.
```

인라인 주석 특성 상, 주석이 너무 간략해져 충분한 정보를 주지 못 하는 경우가 많다. 그러니 특정 변수에 대해 목적을 설명하거나 맥락을 제공할때 사용해야 한다.

### 설명 주석
주석은 해당 코드가 수행하는 작업을 설명하는 것이 아닌, 코드를 적은 의미를 설명하기 위해 존재한다. 예를 들어보자.
```python
current_week_wages *= 1.5 # (1) 현재 주급의 1.5배
current_week_wages *= 1.5 # (2) 초과 근무 시간 반영
```
(1)번 주석을 보자. 우리는 코드만 봐도 1.5배를 곱한다는걸 알 수 있기 때문에 쓸모가 없는 반면, (2)번 주석은 코드의 의미를 제대로 설명해줬다. 이처럼 주석은 코드의 '맥락'을 제공하기 위해 사용해야 한다.

### 요약 주석
여러 줄의 코드를 요약한 간단한 주석을 달아두면, 다른 사람이 보기에 소스 코드를 대충 훑어보고도 어떤 기능을 하는지 개략적으로 파악할 수 있다.

요약 주석은 코드 문단 시작지점에 위치하며, 개략적인 동작을 설명하기 위해 짧은 문구로 로직을 요약해야 한다.

### 코드태그와 TODO 주석
규모가 있는 프로젝트면 형상관리 Tool로 대체 가능하지만, 개인 프로젝트 등의 경우 TODO 주석을 통해 앞으로 해야 될 업무를 상기시킬 수 있다. 
```python
_charge_ion_flux_stream() # TODO: 왜 매주 화요일이면 장애가 발생하는지, 원인 파악 필요
```
TODO 말고도 다음과 같이 다양한 태그를 이용할 수 있다.
* **TODO:** 나중에 해야 할 일
* **FIXME:** 코드의 해당 부분이 전혀 동작하지 않음
* **HACK:** 코드의 해당 부분이 동작하긴 하지만, 개선이 필요
* **XXX:** 간혹 심각한 에러가 발생할 수 있음

태그 뒤에는 당면한 작업이나 문제의 설명이 이어져야 한다. 형상관리 Tool을 사용할 경우 코드태그 주석을 병행해서는 안된다.

---

## 독스트링
독스트링(docstring)은 모듈의 .py 파일 맨 위, class!
나 def 바로 뒤에 이어지는 다중행 주석이다. 정의된 모듈, 클래스 등에 대한 문서를 제공한다. 독스트링은 삼중 큰따옴표(""")를 사용한 다중행 주석을 사용해야 한다.

```python
class Cookie():
"""맛있는 쿠키를 관리하기 위한 클래스.
    다양한 쿠키를 추가하거나, 섭취하거나, 줄 수 있음
    
    Basic Usage::
    
        >> import bakery
        >> c = bakery.Cookie()
        >> c.add("choco")
        
        ... 후략
    """
```

독스트링은 이처럼 대상에 대한 자세한 정보를 제공하며, 처음 본 프로그래머도 쉽게 사용하도록 도움을 준다. 일반적으로 함수의 경우 파라미터, 반환값 등의 정보를 포함한다. 독스트링은 문서를 소스 코드에 통합하기 때문에, 정보의 접근성이 크게 높아져 정보를 쉽게 검토하고 업데이트할 수 있다는 이점이 있다.

## 타입 힌트
많은 프로그래밍 언어들은 **정적 타입(static typing)**을 지원하는 것에 반해, 파이썬은 변수에 어떤 타입이든 저장할 수 있는 **동적 타입(dynamic typing)**을 지원한다.

이는 프로그래밍하기 쉬운 이점이 있지만, 떄때로 치명적인 에러를 불러 일으키기도 한다. 예를 들어,

```python
a = 123.1

... 중략
a = '안녕하세요! 반갑습니다.'

... 중략
b = round(a)
```
하는 상황이 발생하면 어쩌겠는가? 그래서 파이썬에는 타입 힌트(type hint)가 존재한다. 물론 사용은 선택적이지만, 타입 힌트를 사용하면 정적 분석 도구를 사용해 버그를 방지할 수 있다. 우리가 많이 파이썬 개발을 할 때 사용하는 VS Code의 경우, 'Python Type Check'를 이용하면 실시간으로 검사할 수 있다. [링크](https://only-wanna.tistory.com/entry/%ED%8C%8C%EC%9D%B4%EC%8D%AC-static-type-checker)

```python
a: int = 123.1
b: str = "이것은 문자열입니다."

import datetime
noon: datetime.time = datetime.time(12, 0, 0)
```

타입 힌트는 변수 뒤에 콜론(:)과 타입의 이름을 사용해 표시한다. 클래스 같은 객체에도 지정할 수 있는데, 이 때는 클래스 이름을 그래도 표기하면 된다.

### 타입 힌트를 다중 타입으로 설정하기
```python
from typing import Union

spam: Union[int, str, float] = 42
spam = 'hello'
spam = 3.14
```

그렇다면 의도적으로 여러 타입을 사용하는 경우는 어찌할까? 이 경우는 typing 모듈의 Union을 사용하면 된다. Union의 대 괄호 안에 타입의 범위를 지정하면 다중 타입을 사용할 수 있다.

### 리스트, 딕셔너리에서 타입 힌트 사용하기
```python
from typing import List, Union

spam: List[str] = ['Hello', '안녕하세요']
numbers: List[Union[int, float]] = [42, 3.14, 99]
```

리스트, 딕셔너리 같은 경우는 typing 모듈을 이용해서 표기할 수 있다. (리스트: List, 튜플: Tuple, 딕셔너리: Dict, 집합: Set) 물론 이 경우도 Union을 이용한 다중 타입을 이용할 수 있다.