앎을 경계하기

[가짜연구소3기] Data Engineer

[가짜연구소3기] 데이터 엔지니어링 - 46 Decorators

양갱맨 2021. 9. 13. 13:39

주제

데코레이터에 대해 배웠다.


데코레이터

데코레이터를 배우기 전에 짚고 넘어갈 개념 : 중첩함수, nonlocal 변수, 클로저

  • 파이썬은 모든 것을 객체라고 생각한다!
    • 함수도 list, string, dictionary 등등 모든 것들이 다 객체의 개념임!
    • 함수도 변수에 저장할 수 있고 list, dict 등 자료구조의 요소로도 저장 가능하다.
    • 물론 함수를 함수의 인자로도 사용할 수 있다.
    • 함수는 중첩으로 선언하는 것도 가능하다.
      def create_math_function(func_name):
        if func_name == 'add':
          def add(a, b):
            return a + b
          return add
      
        elif func_name == 'subtract':
          # Define the subtract() function
          def subtract(a,b):
            return a-b
          return subtract
      
        else:
          print("I don't know that one")
          
      add = create_math_function('add')
      print('5 + 2 = {}'.format(add(5, 2)))
      
      subtract = create_math_function('subtract')
      print('5 - 2 = {}'.format(subtract(5, 2)))

 

그리고 파이썬에서 중요한 것이 바로 스코프이다.

지역변수와 전역변수의 개념을 이해해야한다.

  • 지역변수 : 변수를 만든 함수 안에서만 사용 가능한 변수
  • 전역변수 : 스크립트 전체에서 접근 가능한 변수
  • nonlocal : 중첩 함수에서 현재 함수 외 바깥 함수의 지역변수
  • built-in : 전역 범위를 넘어 파이썬 내장 범위에 선언됨

클로저(Closures)

non-local 변수를 굳이 알려주지 않아도 내부함수에서 기억해 사용할 수 있는 형태의 함수

클로저에 저장된 값은 원본 객체를 지우고 변경해도 영향받지 않는다.

In [1]: x = 25

In [2]: def foo(value):
   ...:     def bar():
   ...:         print(value)
   ...:     return bar
   ...:

In [3]: my_func = foo(x)

In [4]: my_func()
25

In [5]: my_func.__closure__
Out[5]: (<cell at 0x000001BBAC9FDC70: int object at 0x00007FF875393A20>,)

In [6]: len(my_func.__closure__) # 저장하고 있는 값 개수
Out[6]: 1

In [8]: my_func.__closure__[0].cell_contents # 클로저에 저장된 값 확인
Out[8]: 25

본격 데코레이터 배우기

함수의 동작을 변경하는 함수 주위에 배치할 수 있는 wrapper.

@데코레이터 형식으로 작성한다.

# 함수->일급 객체
def multiply(a,b):
	return a * b
def double_args(func):
	return func

new_multiply = double_args(multiply)
new_multiply(1,5) # ==multiply(1,5), 5
def multiply(a,b):
	return a * b

# 중첩 함수, 클로저 개념!
def double_args(func):
	def wrapper(a,b):
		return func(a,b)
	return wrapper

new_multiply = double_args(multiply)
new_multiply(1,5) # ==multiply(1,5), 5
def multiply(a,b):
	return a * b

# 중첩 함수, 클로저 개념!
def double_args(func):
	def wrapper(a,b):
		return func(a * 2, b * 2)
	return wrapper

multiply = double_args(multiply)
multiply(1,5) # 기존 multiply 덮어씌움, closure에 원본 함수가 저장되어있기 때문에 가능, 20

본격적으로 데코레이터를 사용해보자.

def double_args(func):
	def wrapper(a,b):
		return func(a*2, b*2)
	return wrapper

@double_args
def multiply(a, b):
	return a * b

multiply(1, 5)