def foo(mylist = []):
mylist.append(1)
return mylist
print(foo())
print(foo())
print(foo())
함수 foo
는 인자의 기본값으로 빈 리스트를 갖고, 함수 내부에서 빈 리스트에 1을 추가해서 리턴한다.
우리의 의도대로라면, print(foo())
를 실행할 때마다 실행 결과는 [1]
로 같아야 한다.
그러나, 실제 실행 결과를 보면 아래와 같다.
[1]
[1,1]
[1,1,1]
파이썬에서는 모든것들(숫자, 문자, 함수 등)을 객체로 취급한다.
따라서 파이썬에서의 함수는 하나의 객체이다.
foo
의 매개변수 mylist
는 객체 foo
의 속성으로 존재한다.
즉, foo
를 call할 때마다 새로운 mylist
를 만들어 주는것이 아니라, mylist
를 foo
객체 안에 만들어 두고, 공유하는 것이다.
이것은 인자의 기본값을 mutable한 객체(list, dictionary, class 등)로 정의할 때 의도하지 않은 동작을 발생시킬 수 있다.
immutable한 객체(Number, String, Tuple, None 등)의 경우, 객체 안의 속성으로 공유하더라도, 값이 변하지 않기 때문에 아래와 같이 우리의 의도대로 함수가 동작한다.
def bar(mynumber=3):
mynumber += 1
return mynumber
print(bar())
print(bar())
print(bar())
#결과
4
4
4
foo
함수와 같은 결과가 나타난다.이를 해결하기 위해 파이썬 공식 문서에서는 아래와 같은 방법을 사용하도록 권고하고 있다.
def foo(mylist=None):
if mylist is None:
mylist = []
mylist.append(1)
return mylist
print(foo())
print(foo())
print(foo())
#결과
[1]
[1]
[1]
위와 같이 작성하면 foo
함수가 기본값으로 실행될 때마다 mylist
가 매번 초기화되기 때문에 함수 사이에서 mylist
가 공유되지 않는다.