1
2
3
4
5
6
7
8
9
>>> def f (x, y=[]) :
    y.append(x)
    print(y)
>>> def test () :
    f('a')
    f('a')
    f('a')
>>> test()

cs


9번째 라인의 출력 결과는 어떻게 될까?

위 코드의 결과는 아래와 같다.


1
2
3
4
>>> test()
['a']
['a''a']
['a''a''a']
cs


나는 당연히 ['a']가 세 번 출력될 것이라 예상했는데 이전 값들이 계속 남아 출력되어 적잖이 당황했다.

정황으로 보아 f 함수의 y 변수가 지워지지 않고 계속 남아있는 것으로 보이는데 이해가 되지 않았다.

y 변수는 분명 지역변수로 매번 생성 될텐데 어째서 지워지지 않았을까.


이러한 내용과 관련하여 검색을 해보고 아래와 같은 사실을 알게 되었다.

Default Parameter Values in Python 참고


python에서 함수 인자의 기본값으로 "mutable" 성격의 오브젝트가 선언되고 그 기본값을 통해 변수가 생성될 경우 해당 변수는 static 변수의 성격을 갖게 된다.


일부 사이트에서는 인자의 기본값이 mutable 이면 global 변수가 된다고 하는데,

변수의 life time은 global 이지만 scope이 함수 내부여서 global 변수 보다는 static 변수로 보는 것이 맞을 것 같다.


이러한 이유 때문에 동일한 함수(위 코드에서 f 함수)를 계속 호출하면 매번 y 리스트가 새로 생성되는 것이 아니라, 이전에 호출 되었던 y 변수를 다시 불러와 다시 사용하게 되는 것이다.


리스트, 딕셔너리 뿐만 아니라 클래스와 같은 오브젝트들도 함수 인자의 기본 값으로 사용하게 될 경우 위의 내용과 동일하게 동작한다.


이러한 문제를 해결하기 위한 방법은 여러가지가 있을 것인데 아래 코드와 같이 바꿔서 사용할 수도 있다.


1
2
3
4
5
6
>>> def f (x, y=None) :
    if y is None:
        y=[]
    y.append(x)
    print(y)
 

cs


삽질을 피하기 위해 인자의 기본 값 설정 시에는 가능하면 "mutable" 한 오브젝트는 사용하지 말자.

+ Recent posts