함수 데커레이터와 클로저 - 1

Sanghun Moon·2022년 1월 2일
0

python

목록 보기
3/4

데커레이터라는 표현은 구문 트리를 파싱하고 애너테이션하는 컴파일러 분야에서의 용법과 관련이 크다

함수 데커레이터 : 소스 코드에 있는 함수를 ‘표시’해서 함수의 작동을 개선

데커레이터란?

데커레이터(decorator)는 다른 함수를 인수로 받는 callable

데커레이터는 데커레이트된 함수에 어떤 처리를 수행, 함수를 반환하거나 함수를 다른 함수나 callable 객체로 대체

@decorate
def target():
	print("running target()")

def target():
	print("running target()")

target = decorate(target)

엄밀히 말하면 데커레이터는 편리 구문이다 (syntactic sugar)

→ 그렇지만 런타임에 프로그램 행위를 변경하는 메타프로그래밍을 할 때 데커레이터가 상당히 편함

그래서 데커레이터는...

  • 데커레이트된 함수를 다른 함수로 대체하는 능력
  • 데커레이터는 모듈이 로딩될 때 바로 실행

파이썬이 데커레이터를 실행하는 시점

데커레이터의 핵심 특징 → 데커레이트된 함수가 정의된 직후에 실행

정의된 직후 → 일반적으로 파이썬이 모듈을 로딩하는 시점, 즉 임포트 타임

변수 범위 규칙

case 1

b = 6
def test_f(a):
    print(a)
    print(b)

test_f(3)

>> 3
>> 6

case 2

b = 6

def test_f(a):
    print(a)
    print(b)
    b = 9

test_f(3)

Traceback (most recent call last):
  File "/Users/sanghunmoon/Library/Application Support/JetBrains/PyCharm2021.1/scratches/scratch_4.py", line 8, in <module>
    test_f(3)
  File "/Users/sanghunmoon/Library/Application Support/JetBrains/PyCharm2021.1/scratches/scratch_4.py", line 5, in test_f
    print(b)
**UnboundLocalError: local variable 'b' referenced before assignment**

Process finished with exit code 1

파이썬이 함수 본체를 컴파일할 때 b가 함수 안에서 할당되므로 b를 지역 변수로 판단

생성된 바이트코드를 보면 case 2 에서는 지역 환경에서 변수 b를 가져오려 한다

나중에 test_f(3) 을 호출할 때, test_f 의 본체는 지역변수 b의 값을 가져오려 할 때 b가 바인딩되어 있지 않다는 것을 발견

# case 1

4           0 LOAD_GLOBAL              0 (print)
              2 LOAD_FAST                0 (a)
              4 CALL_FUNCTION            1
              6 POP_TOP

  5           8 LOAD_GLOBAL              0 (print)
             **10 LOAD_GLOBAL              1 (b)**
             12 CALL_FUNCTION            1
             14 POP_TOP
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE

# case 2

4           0 LOAD_GLOBAL              0 (print)
              2 LOAD_FAST                0 (a)
              4 CALL_FUNCTION            1
              6 POP_TOP

  5           8 LOAD_GLOBAL              0 (print)
             **10 LOAD_FAST                1 (b)**
             12 CALL_FUNCTION            1
             14 POP_TOP

  6          16 LOAD_CONST               1 (9)
             18 STORE_FAST               1 (b)
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE

클로저

함수 본체에서 정의하지 않고 참조하는 비전역(nonglobal) 변수를 포함하는 확장 범위를 가진 함수

  • 클로저는 내포된 함수 안에서만 의미가 있음
  • 함수가 익명 함수인지의 여부는 중요하지 않음
  • 함수 본체 외부에 정의된 비전역 변수에 접근 가능

자유변수

지역 범위에 바인딩 되어 있지 않은 변수

어떤 코드블록 안에서 사용되지만, 글로벌 변수도 아니고 그 블록 내에 정의하지도 않은 변수

def make_averager():
	################### CLOSURE START
	series = [] # 자유 변수 (free variable)

	def averager(new_value):
		series.append(new_value)
		total = sum(series)
		return total / len(series)
	################### CLOSURE END

	return averager

→ 클로저는 함수를 정의할 때 존재하던 자유 변수에 대한 바인딩을 유지하는 함수

함수를 정의하는 범위가 사라진 후에 함수를 호출해도 자유 변수에 접근할 수 있음

함수가 비전역 외부 변수를 다루는 경우는 그 함수가 다른 함수 안에 정의된 경우 뿐


출처

전문가를 위한 파이썬
제타위키

해당 글은 전문가를 위한 파이썬을 정리한 글입니다
저작권에 문제가 있으면 삭제하도록 하겠습니다

profile
Python Server Developer

0개의 댓글