해당 내용은 Datacamp의 Data engineering track을 정리했습니다.
Writing Functions in Python의 chapter 3에 대한 내용입니다.
기본적인 내용보다는 강의를 들으면서 처음 알게 된 내용을 위주로 작성했습니다.
해당 포스팅에는 아래의 내용을 포함하고 있습니다.
- function 변수로 할당하기
- global, nonlocal, local 차이
- closure
- decorator
1. Functions are objects
파이썬에서는 함수를 변수로 선언이 가능합니다. 예를 들어, my_function이라는 함수가 있다고 가정해봅시다. 해당 함수를 사용할 때에는 my_function() 형태로 활용할 수 있지만, x = my_function으로 정의하면, x()로 해도 my_function()이 작동 가능합니다.
또한 function을 list 내부에 담았을 때에도 list[0]() 형태로도 함수를 활용 가능합니다. 리스트 이외에도 딕셔너리도 동일하게 접근이 가능합니다.
function을 함수의 인수로도 지정이 가능하고, 함수 내부에 함수를 또 정의할 수도 있습니다.
2. Scope
Scope는 범위라는 의미를 가지고 있는데, 이번 강의에서는 각 변수의 범위와 관련된 local, nonlocal, global에 대한 내용을 다룹니다.
def foo():
x = 10
def bar():
x = 200
print(x)
bar()
print(x)
foo()
위의 함수를 실행했을 때, 결과 값이 어떻게 나오게 될까요? 200과 10이 나올 것입니다. 왜냐하면, foo()를 실행했을 때, x를 10이라는 값을 참조하고 있고, bar()가 실행되면서 x가 200을 참조하여 bar 내부에 있는 print(x)에 의해 200이 출력됩니다. 그 후에 print(x)가 새롭게 실행되는데, 여기에 해당하는 x는 foo()가 처음 실행되었던 부분에서의 x를 불러오게 됩니다. 그래서 10이라는 결과가 출력됩니다. 만약, foo()에서의 x=10을 제외하고 실행한다면, 10 출력되었던 부분에서 x가 정의되어 있지 않다는 에러가 발생하게 됩니다. 기본적으로 함수 내부의 공간을 local로 인식을 하고, 함수 내에서만 해당 변수로의 의미가 존재하게 됩니다.
만약에 위의 함수에서 foo()의 x에 200을 할당하고 싶다면, nonlocal x를 x = 200 바로 전에 넣어주면 됩니다. 비슷한 방식으로 전역 변수로 지정하고 싶다면, global x로 수정할 수 있도록 할 수 있습니다. global과 nonlocal의 차이가 약간 애매모호할 수 있는데, 함수 내부의 함수가 있는 경우, 제일 안쪽에 있는 함수를 local, 그 함수를 감싸는 함수의 영역을 nonlocal, 함수 밖을 global로 이해하시면 편할 것 같습니다. 만약 위의 함수에서 foo() 밑에 print(x)를 하면 당연히 에러가 나오게 됩니다. global 영역에서는 x를 정의하지 않았기 때문이죠.
3. Closures
클로저는 어떤 함수의 내부 함수가 외부 함수의 변수를 참조할 때, 외부 함수가 종료된 후에도 내부 함수가 외부 함수를 참조할 수 있도록 저장하는 함수입니다. 클로저는 .__closure__로 접근할 수 있습니다.
def foo():
a = 5
def bar():
print(a)
return bar
func = foo()
func() #5
type(func.__closure__) # <class 'tuple'>
len(func.__closure__) # 1
func.__closure__[0].cell_contents # 5 (a값)
위의 예시처럼 bar 함수는 외부 함수의 a값을 참조하기 때문에 해당 a 값을 closure에 저장하고 있습니다. 추후에 다시 접근할 때에도 동일한 값을 리턴합니다.
x = 25
def foo(value):
def bar():
print(value)
return bar
my_func = foo(x)
my_func() # 25
del(x)
my_func() # 25
이것처럼 x를 제거한 상태에도 my_func에 이미 참조했던 값을 저장하고 있어서 리턴해줍니다.
4. Decorators
데코레이터는 파이썬에서 함수의 동작을 변경하는 기능을 수행합니다. 함수의 위쪽에 @double_args 처럼 데코레이터를 활용할 수 있습니다.
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) # 20
만약, 여러가지의 함수에 적용할 데코레이터를 만들고 싶다면, 위의 함수처럼 함수 내부에 wrapper를 활용하고, 해당 wrapper를 리턴하는 방식으로 만들 수 있습니다.