본문 바로가기
함수형 프로그래밍/python

별개로 호출될 수 있는 curry 함수 만들기

by thebirghtwide 2021. 7. 20.
안전성 있는 curry? 좀 더 쓰기 편한 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

위는 이전에 작성했던 curry 문 이다. 물론 이 curry문도 curry로서 잘 동작하지만 한 가지 문제점이 있다. 바로 

def curry(func) :
    curry.__func_name__ = func.__name__ 
    f_args, f_kwargs = [], {}  <------------ 변수 설정 및 저장..

처음에 변수를 미리 선언하고 값이 들어올때 마다 추가시키기 때문에 아래 처럼 curry를 decorator로 add 함수를 부르게 되면 (decorator는 추후에 한번 다루기로 하겠다) 

@curry 
def add( x, y ) :
	return x + y
    
print(add(1))
print(add(2))

'''
args (1,) kwargs {}
<function curry.<locals>.f at 0x0000020C57BF8558>
args (2,) kwargs {}
3
'''

 

위 처럼 add(1)에서 1를 가지고 있다가 add(2)를 한번 더 호출했을 때 두 변수의 합이 산출되는 것을 확인 할 수 있다. 

위 처럼 사용하면 물론 장점도 있지만, 함수가 계속 변수를 저장하고 있다는 점에서 같은 함수를 다시 재사용하고 싶을 때 현재 그 함수가 저장된 변수가 있는지 없는지 확인해야 하는 번거로움을 가지게 된다. 

 

좀 더 직관적으로 쓰기 편한 curry 

따라서 알고리즘을 좀 더 쉽게 풀기 위해서 변수를 저장하지 않는 형식으로 add(1)(2) 라고 바로 호출할때 만 사용 되는 curry 문을 만들어 보자 

def curry(func) :
    curry.__func_name__ = func.__name__ 
    # f_args, f_kwargs = [], {} <---- 단순하다 변수를 선언해준 부분만 주석처리
    def curried(*args, **kwargs) :

        def f(*args2, **kwargs2) :
            nonlocal args, kwargs
            args += args2
            kwargs.update(kwargs2)
            return curried(*args, **kwargs)

        if len(args) + len(kwargs) >= func.__code__.co_argcount  : 
            return func( *args, **kwargs)
        else :
            return f

    return curried

새롭게 작성한 curry 문이다. 보면 그렇게 크게 변한것이 없어 보인다. 위에 변수를 선언한 부분을 빼면 그렇게 크게 변한것이 없어보인다. 실제로 사용해보면서 확인해보자 

@curry 
def add( x, y ) :
	return x + y

print(add(1))
print(add(2))

'''
<function curry.<locals>.curried.<locals>.f at 0x0000020C549E9318>
<function curry.<locals>.curried.<locals>.f at 0x0000020C57CE6168>
'''

똑같이 add 함수를 적용하여 add(1), add(2)를 각각 출력 시켜 보았다. 출력을 보면 각각 별개의 주소를 가진 함수를 출력하는 것을 확인 할 수 있다. 우리는 이로서 같은 함수 이름이지만 독립적인 curry 함수를 만들어 사용할 수 있게 되었다. 물론 위 처럼 쓰는 방식이 마냥 좋은 것은 아니지만 앞으로 알고리즘을 문제를 풀 때 조금 더 편하게 사용할 수 있다는 장점을 가지고 있다. 

댓글