Python 함수의 기본값은 상수 혹은 None이어야 한다

파이썬에서 함수 선언부는 런타임에 한 번만 실행된다.
따라서 함수에 기본값을 넣을 때는 주의해야 한다. 
(그냥 반드시 상수를 넣자고 생각하는 게 맘 편하고, 오류가 더 적을 것 같다)

문제 있는 코드 1)


from datetime import datetime
def log(msg, dt=datetime.now()):
    print("{}: {}".format(dt, msg))

def는 한 번 실행되고 그 이후엔 메모리에 상주하기 때문에 
이 때 dt는 항상 같은 값(log 함수가 만들어진 시점의 time)만 출력된다.
따라서 아래와 같이 변해야한다.

개선 된 코드 1)

def log2(msg, dt=None):
    dt = dt or datetime.now()
    print("{}: {}".format(dt, msg))
기본값은 None을 가리킨다.
함수 실행시 keyword argument로 dt값이 있으면 dt값을 쓰고 dt값이 없으면 datetime.now()를 호출한다.


다음으로는 Mutable한 객체가 함수의 기본값일 때 생기는 문제이다.

문제 있는 코드 2) 

my_list = [1,2,3]
def log3(msg=my_list):
    print(msg)

이 경우엔 my_list의 refence가 넘어가는거라 my_list가 변경이 되면 msg의 기본값도 변하게 된다.
예를들어 그냥 log2()를 실행하면 [1,2,3]을 출력하지만
my_list.append(4)를 실행한 후에 log2()를 실행하면 [1,2,3,4]가 출력된다.
이는 기본 값이 Mutable한 객체이기 때문에 발생하는 문제다.


개선 된 코드 2)
따라서 [1,2,3]을 출력하고 싶으면 아래와 같이 하거나 

def log3(msg=[1,2,3]):
    print(msg)


혹은 Immutable한 tuple 객체를 쓰면 된다.

my_list = (1,2,3,)
def log3(msg=my_list):
    print(msg)

댓글

이 블로그의 인기 게시물

로컬 Tomcat 서버 실행속도 개선

2019.05.23 - SQLAlchemy 의 객체 상태 관리 (expire, refresh, flush, commit) 에 관한 이해

2020.02.17 Python의 multiprocessing 중 Pool.map(), chunksize에 관한 내용