• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

친절한 답변 정말감사합니다. 한번에 이해됐습니다. 질문하나 더있습니다!

20.01.06 22:16 작성 조회수 158

2

def time_checker(func):
    def inner_function(*args, **kwargs):
        start_time=time.time()
       result=func(*args,**kwargs) 
        end_time=time.time()
        print("func:{}, time:{}".format(func.__name__,end_time-start_time))
        return result
    return inner_function
이 중첩함수에서
바깥함수는 안쪽함수를 리턴하고
안쪽함수는 result를 리턴하는데
여기서 result는 인자로 받은 함수를 실행한 결과값아닌가요?
결국 time_checker는 func(*args,**kwargs)를 출력한다고 생각을 했는데
print(test1()) 과 print(time_checker(test1()))값이 다릅니다
전자는 None이 출력되었고
후자는 <function time_chker.<locals>.inner_function at 0x000001C3C51E3A60>이 출력되었습니다
제가 뭘 잘못알고있는지 알려주시면 감사하겠습니다!

답변 5

·

답변을 작성해보세요.

0

위의 코드가 클로저를 제대로 사용하신 방법으로 나온 결과가 맞습니다.

결론적으로 inner_func 내부의 func() 가 실행이 되어야만 res 에 결과가 들어갈테고 func() 가 실행되기 위해선 outer_func() 가 실행되야하고 outer_func()가 실행되기 위해선 f = outer_func(add) 이렇게 할당한 f 가 f() 이렇게 실행이 되어야 합니다.

여기서 중요한 부분은 어쨌든 f 라는 변수에 add 함수의 원형 그대로를 저장해서 내가 사용하고 싶을때 사용했다는 사실입니다. 

f = outer_func(add) 

이렇게 선언을 했을때는 함수는 실행되지 않습니다. 모든게 그냥 기억만 되고 있는 상황입니다. 이걸 실행하기 위해선 f() 라고 해야만 실행이 되게 되는거죠. f 는 add 함수의 모든 기능을 수행 할 수 있게 됩니다.

여기서 중요한 사실 한가지는 왜 이렇게 사용하느냐 하는 내용입니다. 사실 클로저를 사용하는 또 한가지 예로는 예를 들어 add 함수는 내가 만든 함수가 아닌경우에 코드를 수정하지 못한다고 가정한 경우 add 함수에 평균값을 같이 구해주는 기능을 추가 한다고 가정하겠습니다. 그럼 물론 아래처럼 간단하게 

result = add(2, 5) / 2

이렇게 표현할 수도 있지만 만약 어떤 내용이 위보다 더 복잡한 추가 연산이 필요한경우 그러면서 함수 원형을 내가 수정하지 못하는 경우 위처럼 클로저를 활용해서

def _average(func):
    def inner_func(*args, **kwargs):
        res = func(*args, **kwargs)
        # .... res 결과에 대한 추가 기능....
        average = res / len(args[0])
        return {
            "hap": res,
            "average": average
            }
    return inner_func

def add(number_list):
    return sum(number_list)

average = _average(add)
print(average([10, 20]))

위처럼 내가 원하는 연산 혹은 기능을 추가하여 add 함수에 새로운 기능을 부여할수도 있습니다. 물론 이런 기능을 능숙하게 활용하기 위해선 상당히 많은 다양한 상황에 대한 경험이 필요합니다. 단지 클로저를 이해했다고 해서 쉽게 구현하고 적용하는건 쉬운 문제는 아니라고 생각됩니다. 프로그래밍의 방법은 정해진 법칙이 없기 때문에 더 어렵습니다. 내용을 이해하시는 것도 중요하지만 더 중요한건 이걸 왜 쓰냐를 이해하고 공감하시는게 더 중요하다고 생각됩니다.

저도 파이썬으로 프로그램을 만들때 클로저를 직접 구현해서 사용하는 경우는 많지 않습니다. 클로저 활용을 많이 하는 경우는 보통 라이브러리를 제작하거나 할때 주로 많이 사용됩니다. 아무튼 참고가 되셨으면 좋겠습니다.

0

윤태영님의 프로필

윤태영

질문자

2020.01.10

def outer_func(func):
    def inner_func(*args, **kwargs): # *로 튜플을 받고 **로 딕셔너리를 받는다. 포인터로 여러 요소를 한번에 받을수있다
        print("func name =", func.__name__)
        print("args=",args)
        print("kwargs=",kwargs)
        res = func(*args, **kwargs)
        print("res=",res)
        return res
    return inner_func

def add(a,b,**info): #integer와 **kwargs를 받는다
    for key, value in info.items():
        print("{} , {}".format(key,value),end='   ') 
    return a+b
#클로저 : 변수에 함수를 선언 후 변수를 함수처럼 사용
f=outer_func(add) #f에 outer_func(add) 저장
print('\n')
result = f(2,3,taeyoung = 40, zayoung = 60) #args에 2,3  kwargs에 뒤에 저장
print('\n')
print(result)

번거롭게해서 죄송합니다

0

res = func(*args, **kwargs) 는 결국 outer_func(func) 가 호출이 되야 실행될테고 outer_func를 어떻게 실행시켰는지가 코드에 나와있지 않은것 같습니다. 코드 전체를 올려주시면 살펴보겠습니다.

0

윤태영님의 프로필

윤태영

질문자

2020.01.08

def outer_func(func):
    def inner_func(*args, **kwargs): 
        print("func name =", func.__name__)
        print("args=",args)
        print("kwargs=",kwargs)
        res = func(*args, **kwargs)
        print("res=",res)
        return res
    return inner_func
def add(a,b,**info): 
    for key, value in info.items():
        print("{} , {}".format(key,value),end='   ')
    return a+b

이 코드의 경우엔

위와같이 func(*args, **kwargs)를 res에 할당하고

print(res)를 하면 함수의 실행결과인 숫자가 출력됩니다

type(res)를 해도 int가 나옵니다

위의 질문과 다른상황인가요?

0

파이썬의 클로저는 네임바인딩을 하는 기술로서 말 그대로 함수를 변수처럼 사용할 수 있는 성질이 있습니다.

그래서 말씀하신 print(time_checker(test1())) 은 test1() 함수가 실행되는게 아니라 할당만 해놓은 상태가 되는겁니다.

쉽게 변수에 선언을 해놓은 상태라고 보시면 됩니다. 

따라서 리턴값은 <function time_.......> 이런식으로 할당된 함수가 저장된 값만 나오고 그 형태가 function 이라고 출력됩니다. 

import time

def time_checker(func):
    def inner_function(*args, **kwargs):
        start_time=time.time()
        result=func(*args,**kwargs) 
        end_time=time.time()
        print("func:{}, time:{}".format(func.__name__,end_time-start_time))
        return result
    return inner_function


def test1():
    return True


# 이렇게 하는건 그냥 선언만 해놓은 상태가 됩니다.
# 물론 test1() 은 함수를 실행하는 형태기때문에 아래 문법은 오류 입니다.
time_checker(test1())

# 이렇게 선언하는게 맞습니다만 저장될 변수가 없습니다.
time_checker(test1)

# 따라서 해당 함수를 변수에 저장하고 해당 변수를 함수처럼 사용하게 됩니다.
a = time_checker(test1)
print(a())

위의 코드를 보시면 좀 더 이해하시기 좋을꺼 같아서 한번 만들어봤습니다. 항상 궁금하신건 언제든 질문 주시기 바랍니다. ^^