python curry update
이전에 작성했던 python curry 문이다.
def curry(func) :
curry.__func_name__ = func.__name__
f_args, f_kwargs = [], {}
def f(*args, **kwargs) :
nonlocal f_args, f_kwargs
if args or kwargs :
print("args", args, "kwargs", kwargs)
f_args += args
f_kwargs.update(kwargs)
return f
else :
print( f_args, f_kwargs)
result = func( *f_args, **f_kwargs)
f_args, f_kwargs = [], {}
return result
return f
def add (a, b) :
return a + b
add2 = curry(add)
print(add2(1)(2)())
위 코드를 보면 마지막에 print(add2(1)(2)()) 이렇게 작성함으로서 값을 작성한 것을 알 수 있다...
이를 보면 굉장히 번거로워 보인다는 것을 알 수 있다. 함수를 실행 시키기 위해 add2(1)(2) 는 함수 변수만 선언된 상태이다
>>> print(add2(1)(2))
<function curry.<locals>.f at 0x000002C2D9A89B88>
직접 프린트 해보면 다음과 변수 유형 (즉, 함수)과 객체의 메모리 주소 (0x10efa6e50)가 표시된다.
여기서 추가적으로 함수 값을 호출하려면 () 괄호를 추가로 넣어주어야
>>> print(add2(1)(2)())
3
다음 과 같이 값이 리턴되는 것을 알 수 있다.
| 문제점 |
우리는 좀 더 함수 curry를 사용하고 싶다. add(1)(2)만 써서 말이다. 이를 위해서는 함수 코드를 조금 수정해볼 필요가 있다.
def curry(func) :
curry.__func_name__ = func.__name__
f_args, f_kwargs = [], {}
def f(*args, **kwargs) :
nonlocal f_args, f_kwargs
if args or kwargs : <------- 조건
print("args", args, "kwargs", kwargs)
f_args += args
f_kwargs.update(kwargs)
return f
else :
print( f_args, f_kwargs)
result = func( *f_args, **f_kwargs)
f_args, f_kwargs = [], {}
return result
return f
curry 함수에서 f함수의 조건을 살펴 보면
if args or kwargs : 일 경우 즉, func 함수 이후 받은 매개변수로 입력받는 변수들이 있을 때 마다
f_args, f_kwargs를 업데이트 혹은 추가 하고
else : 아니면 func함수에 받았던 저장해 두었던 변수 f_args, f_kwargs을 넣어 return 하겠다는 뜻이다.
여기서 보이는 문제점은 함수의 호출조건이 args, kwargs가 빈 값일 때 그 때서야 모아두었던 함수의 호출값을 리턴해준다는 것이다. 한 가지의 조건만 추가한다면 func의 변수 갯수 만큼 매개변수가 들어 왔을 때 함수를 호출하여 값을 리턴해 줄 수 있을 것이다.
| 문제해결 |
일단 기존 코드의 조건문을 살펴 보자
def f(*args, **kwargs) :
nonlocal f_args, f_kwargs
if args or kwargs :
print("args", args, "kwargs", kwargs)
f_args += args
f_kwargs.update(kwargs)
return f
else :
print( f_args, f_kwargs)
result = func( *f_args, **f_kwargs)
f_args, f_kwargs = [], {}
return result
현재 단순히 args or kwargs 가 있는지 없는지만 보고 있는 상태에서
하나의 조건을 추가하여 func의 매개변수 길이 만큼 들어 왔을 때 제어 하는 로직을 만들어보자
if args or kwargs :
print("args", args, "kwargs", kwargs)
f_args += args
f_kwargs.update(kwargs)
return f
args 혹은 kwargs를 신규로 받았을 때 f_args, f_kwargs를 추가하거나 업데이트 하고 바로 함수 f 를 호출하고 있다. 여기서 조건을 추가해보자
if args or kwargs :
print("args", args, "kwargs", kwargs)
f_args += args
f_kwargs.update(kwargs)
if len(f_args) + len(f_kwargs) >= func.__code__.co_argcount :
result = func( *f_args, **f_kwargs)
f_args, f_kwargs = [], {}
return result
return f
지금 보면 if len(f_args) + len(f_kwargs) >= func.__code__.co_argcount : 조건을 추가한 것을 볼 수 있다.
func.__code__.co_argcount 의 뜻은 함수의 총 매개변수의 갯수를 가져온다는 뜻이다. 예를 들어
def add (a, b, name ='foo', car = 'in') :
return a + b
add.__code__.co_argcount
4
위 처럼 사용 될 수 있다. 즉 if len(f_args) + len(f_kwargs) >= func.__code__.co_argcount : 조건의 뜻은 현재까지 받은 총 매개변수의 합이 함수의 매개변수의 합보다 크거나 같다면 바로 결과를 출력 해주겠다는 뜻이다. 그럼 이렇게 코드를 수정해서 curry문을 만들어 보면
def curry(func) :
curry.__func_name__ = func.__name__
f_args, f_kwargs = [], {}
def f(*args, **kwargs) :
nonlocal f_args, f_kwargs
if args or kwargs :
print("args", args, "kwargs", kwargs)
f_args += args
f_kwargs.update(kwargs)
if len(f_args) + len(f_kwargs) >= func.__code__.co_argcount :
result = func( *f_args, **f_kwargs)
f_args, f_kwargs = [], {}
return result
return f
else :
print( f_args, f_kwargs)
result = func( *f_args, **f_kwargs)
f_args, f_kwargs = [], {}
return result
return f
def add (a, b) :
return a + b
add2 = curry(add)
print(add2(1)(2))
'''
args (1,) kwargs {}
args (2,) kwargs {}
3
'''
다음과 같이 add2(1)(2)를 바로 사용 할 수 있게 된다. 이제 좀 더 curry 다운 curry가 완성 되었다.