low
parameter 분석하기파이썬에서 함수를 정의하는 예시를 들어보자.
def print_params(a, b=3):
print(a, b)
print_params
선언에서 소괄호 내부에 사용된 a
, b
가 이 함수의 parameter 이다. a는 함수를 호출할 때 필수적인 parameter 이므로 required parameter 이고, b
는 호출 시 생략되어도 default 값인 3
이 할당됨으로 optional patameter 이다.
print_params(3, b=5)
# 3, 5
함수를 호출함에 있어 괄호 안에 3
, b=5
가 들어가 있는 모습을 볼 수 있다. 이렇게 함수가 호출되기 위해 전달되는 것들을 argument 라 한다.
3
은 첫 번째 argument이고, 이에 따라 첫 번째 paramter 인 a
에 할당된다. 따라서 3
을 positional argument 라 한다.
반면 b=5
는 함수의 b
라는 parameter에 keyword 형태로 할당되므로 이를 keyword argument라 한다.
여기까지 보면 required paramter == positional argument고,
optional paramter == keyword argument 라고 생각할 수 있다.
하지만 paramter 는 함수 선언 시에 사용되는 개념이고, argument 는 호출 시에 사용되는 개념이기 때문에 둘을 구분할 필요가 있다.
print_params(b=5, a=3)
# 3, 5
위에서는 b=5
, a=3
모두 keyword argument 로 사용되었고,
print_params(3, 5)
# 3, 5
여기서는 3
, 5
모두 positional argument 로 사용되었다.
함수를 선언할 떄 optional parameter 는 requred parameter 보다 앞에 위치할 수 없다.
def print_params(b=3, a):
print(a, b)
# 에러 발생!
# SyntaxError: non-default argument follows default argument
비슷하게 함수를 호출할 때 keyword argument 는 positional argument 보다 앞에 위치할 수 없다.
print_params(b=3, 5)
# 에러 발생!
# SyntaxError: positional argument follows keyword argument
pytorch 의 randint
함수의 doc을 보다 이상한 점을 발견했다.
torch.randint(low=0, high, size, *, generator=None, out=None, dtype=None, layout=torch.strided,
device=None, requires_grad=False) → Tensor
(중간의 * 기호는 그 뒤의 parameter 는 호출 시 모두 keyword argument이여야 함을 의미한다.)
doc의 설명만 보면, low
는 optional 이고, 실제로 잘 작동한다. 하지만 분명 optional은 required 보다 뒤쪽에 위치해야 하는데, 뭔가 잘못된 것일까?
torch.randint()
코드를 그대로 실행해 보면 다음과 같은 error message를 볼 수 있다.
TypeError: randint() received an invalid combination of arguments - got (), but expected one of:
- (int high, tuple of ints size, *, torch.Generator generator, Tensor out, torch.dtype dtype, torch.layout layout, torch.device device, bool pin_memory, bool requires_grad)
- (int high, tuple of ints size, *, Tensor out, torch.dtype dtype, torch.layout layout, torch.device device, bool pin_memory, bool requires_grad)
- (int low, int high, tuple of ints size, *, torch.Generator generator, Tensor out, torch.dtype dtype, torch.layout layout, torch.device device, bool pin_memory, bool requires_grad)
- (int low, int high, tuple of ints size, *, Tensor out, torch.dtype dtype, torch.layout layout, torch.device device, bool pin_memory, bool requires_grad)
즉 randint
함수는 네 가지 종류의 input에 대해 동일한 출력을 낼 수 있게 구현된, 일종의 다형성(Polymorphism)을 갖고 있는 함수라고 볼 수 있다.
실제로 아무리 개떡같이 호출해도 잘 작동하는 모습을 확인할 수 있다.
torch.randint(0, 5, (2, 2))
torch.randint(5, (2, 2))
torch.randint(low=0, high=5, size=(2, 2))
torch.randint(high=5, size=(2, 2))
torch.randint(size=(2, 2), high=5)
torch.randint(high=5, size=(2, 2), low=0)
torch.randint(size=(2, 2), low=0, high=5)
torch.randint(0, size=(2, 2), high=5)
# 모두 같은 같은 동작을 한다.
그래서 이러한 다형성을 어떻게 구현한건지 알아보고자 source code를 뒤져보았지만, 코드가 꼬리에 꼬리를 무는 형태라 바로 이해하기가 힘들었다. 일단 parameter와 argument에 대해 정리한 것에 의의를 두고, 이후에 다시 정리해보자.