인프런 커뮤니티 질문&답변

욕망의햄버거님의 프로필 이미지

작성한 질문수

파이썬 중급

메타 프로그래밍 3

def attach_wrapper의 return func를 하는 이유?

24.06.09 13:19 작성

·

109

·

수정됨

0

안녕하세요 강사님!

좋은 강의 정말 잘 듣고 있습니다. 지난 질문에도 친절하게 답변 달아주셔서 감사의 말씀 드립니다.

이번 메타프로그밍 3.1절을 들으면서 잘 이해가 안되는 부분이 있어서 이렇게 질문글을 작성합니다.

질문은 다음과 같습니다.

Q1. attach_wrapper가 return 하는 func는 누구인가? 최종적으로 그 func는 누가 받는가?

def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func

위의 def attach_wrapper@attach_wrapper(wrapper) 형태로 데코레이트하면, func=None일 때 partial()을 통해서 def attach_wrapper 함수 객체 본인을 return 해서 첫번째 인자인 objwrapper로 고정시키는 것까지 이해를 했습니다.

func=None이 아니면 setattr()을 통해, obj가 갖고 있는 어트리뷰트 func의 이름을 인자로 받은 func로 값을 셋팅하는 것까지도 이해를 했습니다.

그런데 최종적으로 return 되는 게 func라는 것이 잘 이해가 되지 않습니다. return 되는 func를 누가 받는걸까요?

func를 유추하기까지 저의 사고 흐름은 아래와 같았습니다.

@attach_wrapper(wrapper)
def set_level(newlevel):
    nonlocal level
    level = newlevel

def set_level 이 데코레이트 되는 내부 사정은 set_level = attach_wrapper(wrapper)(set_level) 이 될텐데요.

set_level = attach_wrapper(wrapper)(set_level) 에서 attach_wrapper(wrapper)는 partial()을 통해 def attach_wrapper 본체가 return 되었기 때문에, 데코레이트 되는 내부 사정을 달리 표현하면 set_level = attach_wrapper(obj=wrapper, func=set_level) 라고 이해를 했습니다.

그러면.. attach_wrapper(obj=wrapper, func=set_level)return 하는 게 func인데, set_level = func 이니까.. set_level = set_level 이 되는건가요?

 
추가 질문
def attach_wrapper 함수에서 return func를 주석처리 하고 실행을 해도 결과가 똑같이 나오는데 이유를 잘 모르겠습니다.. 어째서 return func가 아무런 효용이 없었던 걸까요..?

혹시 제가 잘 못 이해한 부분이 있다면 어김없이 피드백 부탁드리겠습니다!

(아래에는 출력 결과물을 첨부하였습니다.)

"""
# return func 주석 처리 후 결과

DEBUG:__main__:add
DEBUG:__main__:Add called
WARNING:__main__:Add called
DEBUG:__main__:countdown
CRITICAL:__main__:countdown
DEBUG:__main__:countdown2
CRITICAL:__main__:countdown2
5
5
5
countdown 0.009128093719482422
countdown 0.007673978805541992
countdown2 0.0056438446044921875
countdown2 0.005079030990600586                                    
---
# 원본 코드 실행 결과

DEBUG:__main__:add
DEBUG:__main__:Add called
WARNING:__main__:Add called
DEBUG:__main__:countdown
CRITICAL:__main__:countdown
DEBUG:__main__:countdown2
CRITICAL:__main__:countdown2
5
5
5
countdown 0.007693052291870117
countdown 0.006663084030151367
countdown2 0.005110979080200195
countdown2 0.0052149295806884766

"""

답변 1

0

인프런 AI 인턴님의 프로필 이미지

2024. 06. 11. 13:21

안녕하세요, 인프런 AI 인턴입니다.

attach_wrapper 함수의 return func 부분은 이 함수를 데코레이터로 사용할 때 중요한 역할을 합니다. 함수 데코레이터는 보통 원래 함수를 받아서 어떤 처리를 한 뒤에 함수를 반환하는 구조를 가집니다. 이 때, 반환되는 함수가 원래의 함수이거나 원래 함수에 어떤 기능이 추가된 새로운 함수가 될 수 있습니다.

return func가 있을 경우, 데코레이터는 func 함수에 추가적인 처리(예: 함수에 어떤 속성을 추가하는 등)를 한 후에 원래 함수 func를 그대로 반환합니다. 이로 인해 func의 정의가 변경되거나 추가된 속성을 유지하면서, 함수의 호출 가능성을 그대로 유지할 수 있습니다.

@attach_wrapper(wrapper) 를 사용한 경우, return funcsetattr을 통해 obj에 함수 func의 이름으로 속성을 추가한 후에 원래의 함수 func를 반환함으로써, 원래 함수 func에 대한 참조를 유지하게 합니다. 따라서 set_level = attach_wrapper(wrapper, func=set_level)에서 funcset_level 자기 자신을 가리키고, 이는 setattr을 통해 wrapperset_level 함수를 속성으로 추가한 후, set_level 함수 자체를 반환하는 것을 의미합니다.

추가 질문에 대한 답변으로, return func을 주석 처리하고 실행해도 결과가 같게 나오는 것은 특정 상황에서는 반환값을 명시적으로 사용하지 않기 때문일 수 있습니다. 예를 들어, 만약 attach_wrapper가 데코레이터로 사용되어 함수에 추가적인 처리만 하고, 실제로 그 함수가 다시 사용되지 않는다면 (즉, 반환된 함수를 다른 곳에서 호출하거나 참조하지 않는다면) return func가 생략되어도 코드 실행에 큰 차이가 없을 것입니다. 그러나, 함수의 반환값을 기대하거나 이후에 해당 함수를 다시 사용할 필요가 있는 경우에는 return func이 중요한 역할을 합니다. 따라서 특정 상황에 따라 return func의 유무가 결과에 영향을 주지 않을 수도 있으나, 일반적으로는 함수 데코레이터에서는 원래 함수를 반환하는 것이 좋은 관례입니다.

임의의 코드나 상황에 따라서는 return func이 명확하게 필수적인 역할을 하지 않을 수 있습니다만, 데코레이터의 기본적인 구조와 원칙을 따르는 것이 바람직합니다. 이해가 되지 않는 부분이 있다면 추가적인 질문을 주시길 바랍니다.