종종 키워드 인자의 값으로 정적으로 정해지지 않는 타입의 값을 써야 할 때가 있다.
from time import sleep
from datetime import datetime
def log(message, when=datetime.now()):
print(f'{when}: {message}')
log('안녕')
2021-02-23 00:57:48.924599: 안녕
log('다시 안녕!')
2021-02-23 00:57:48.924599: 다시 안녕!
디폴트 인자는 함수가 정의되는 시점에 한번 호출되므로 타임스탬프는 고정
디폴트 값으로 None을 지정하고 실제 동작을 독스트링에 문서화해야 함
def log(message, when=None):
"""메시지와 타임스탬프를 로그에 남긴다.
Args:
message: 출력할 메시지.
when : 메시지가 발생한 시각(datetime).
디폴트 값은 현재 시간이다.
"""
if when is None:
when = datetime.now()
print(f'{when}: {message}')
log('안녕')
2021-02-23 01:00:32.705004: 안녕
log('다시 안녕!')
2021-02-23 01:00:35.008693: 다시 안녕!
디폴트 인자 값으로 None을 사용하는 것은 인자가 가변적인 경우 특히 중요하다.
예를 들어 JSON 데이터로 인코딩된 값을 읽으려고 하는데, 데이터 디코딩에 실패하면 디폴트로 빈 딕셔너리를 반환하고 싶다.
import json
def decode(data, default={}):
try:
return json.loads(data)
except ValueError:
return default
foo = decode('잘못된 데이터')
foo['stuff'] = 5
bar = decode('또 잘못된 데이터')
bar['meep'] = 1
print(foo)
{'stuff': 5, 'meep': 1}
print(bar)
{'stuff': 5, 'meep': 1}
딕셔너리가 디폴트 파라미터로 같기 때문에 동일한 객체를 쓰게된다.
def decode(data, default=None):
"""문자열로부터 JSON 데이터를 읽어온다.
Args:
data: 디코딩할 JSON 데이터.
default: 디코딩 실패 시 반환할 값이다.
디폴트 값은 빈 딕셔너리다.
"""
try:
return json.loads(data)
except ValueError:
if default is None:
default = {}
return default
foo = decode('잘못된 데이터')
foo['stuff'] = 5
bar = decode('또 잘못된 데이터')
bar['meep'] = 1
print(foo)
print(bar)
{'stuff': 5} {'meep': 1}
이 방법은 타입 애너테이션을 사용해도 잘 작동한다.
from typing import Optional
def log_typed(message: str, when: Optional[datetime]=None) -> None:
"""메시지와 타임스탬프를 로그에 남긴다.
Args:
message: 출력할 메시지.
when : 메시지가 발생한 시각(datetime).
디폴트 값은 현재 시간이다.
"""
if when is None:
when = datetime.now()
print(f'{when}: {message}')
log_typed('안녕')
2021-02-23 01:06:29.832369: 안녕