삽질로 알아보는 파이썬과 루비의 기본 매개변수
Default Argument X (Python, Ruby)

파이썬과 루비의 문법 차이로 인한 버그를 당한적은 자주 있었지만 글로 다룰 생각까진 (게을러서) 하지 않았다. 하지만 아래의 글을 읽고 파이썬와 루비의 차이로 인한 버그를 정리해보면 재밌을거라고 생각했다. 그래서 써보기로 했다.

루비와 파이썬에서 함수 호출과 함수 참조에 대한 차이

기본 매개변수를 이용해서 낚시를 해보자. (얼마나 낚일지는 모르지만) Default argument 를 남들이 기본 매개변수라고 번역하길래 기본 매개변수라고 적었지만 디폴트 매개변수, 기본 인자 등등으로도 불리는거같다. 용어를 하나로 합치려고 default argument 만을 사용하겠다.

문제1. 다음 코드의 실행 결과는?

간단한 파이썬, 루비 코드이다. Default parameter에는 현재 시간이 들어간다. 현재 시간을 찍는 함수를 호출하고 1초 쉬고 다시 현재 시간을 찍는 함수를 부른다. 어떤 실행 결과가 나올지 생각해보자.

#!/usr/bin/env python

import datetime
import time

def run(now = datetime.datetime.now()):
    print(now)

run()
time.sleep(1)
run()
#!/usr/bin/env ruby

require 'time'

def run(now = Time.now())
  puts now
end

run
sleep 1
run
$ python default_argument.py
2016-03-04 00:42:59.921858
2016-03-04 00:42:59.921858
$ ruby default_argument.rb
2016-03-04 00:43:01 +0900
2016-03-04 00:43:02 +0900

파이썬에서는 같은 시간이 2번 찍혔다. 루비에서는 1초 차이나는 시간이 찍혔다. 파이썬에서는 default argument는 미리 계산된 값을 사용하고 루비에서는 함수 호출할때 계산하는거같다.

문제2. 다음 코드의 실행 결과는?

함수 기본값은 언제 계산될까? 이를 확인하기 위해서 간단한 코드를 짰다.

“foo called” 를 출력하는 foo() 라는 함수를 만들었다. foo() 를 default argument로 사용하는 bar() 라는 함수를 만들었다. foo(), bar() 는 만들었을뿐 실제로 호출하진 않았다. 파이썬과 루비의 출력 결과는?

#!/usr/bin/env python

def foo():
    print("foo called")

def bar(a = foo()):
    print("bar called")
#!/usr/bin/env ruby

def foo
  puts "foo called"
end

def bar(a = foo())
  puts "bar called"
end
$ python initial.py
foo called
$ ruby initial.rb

함수를 호출한적이 없는데 파이썬에서는 “foo called” 가 찍혔다. 루비는 foo(), bar() 로 인한 출력이 없다. 파이썬에서는 소스를 읽으면서 default argument를 계산하나보다.

Language specification

“원래 파이썬과 루비는 이렇게 행동하는게 정상입니다” 라고 끝내면 심심하니 언어 스펙을 뒤져보자.

Python

파이썬 3.5 Language Reference 를 뒤져보면 함수 기본값과 관련된 정보를 찾을 수 있다. 8.6. Function definitions 에 나와있다. https://docs.python.org/3.5/reference/compound_stmts.html#function-definitions

Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call…

파이썬에서는 Default argument를 Default paramter value 라고 부른다. default paramter value는 함수가 정의될때 평가되서 정해지고 이후 함수 호출에서는 미리 계산된 값을 사용한다.

Ruby

Programming Languages — Ruby IPA Ruby Standardization WG Draft August 25, 2010 를 참고했다. https://www.ipa.go.jp/files/000011432.pdf 13.3.2 Method parameters , 13.3.3 Method invocation 에서 Default argument와 연관된 것을 찾을 수 있다.

13.3.2 Method parameters

Optional parameters: These parameters are represented by optional-parameters. Each optional parameter consists of a parameter name represented by optional-parameter-name and an expression represented by default-parameter-expression. For each optional parameter, when there is no corresponding argument in the list of arguments given to the method invocation, the value of the default-parameter-expression is used as the value of the argument.

13.3.3 Method invocation

7.i. For each optional parameter POi to which no argument corresponds, evaluate the default-parameter-expression of POi, and let X be the resulting value.

루비에서는 Default argument를 Optional parameter 라고 부른다. 함수 호출 시점에 optional parameter에 대응되는 argument가 넘어오지 않으면 (함수 호출시 기본값을 대신할 값을 넣지 않은 경우) default parameter expression을 평가해서 인자로 사용한다.


comments powered by Disqus