Programming Terms: First-Class Functions를 유투브에서 보고 정리합니다.
- First-Class Functions
- Closures
- Decorators
First-Class Functions: A Programming language is said to have first-class functions if it treats functions as first-class citizens
First-Class Citizen (Programming): A first-class citizen (sometimes called first-class objects) in a programming language is an entity which supports all the operations generally available to other entities. These operations typically include being passed as an argument, returned from a function, and assigned to a variable.
프로그래밍 언어에서 함수들을 first-class citizens로 취급하면 first-class functions이 있다고 말하는데, 이 first-class citizen는 argument로 전달이 가능하고 function에서 return될 수 있으며 변수에 할당 가능한 객체들을 의미한다.
즉, 함수가 argument로 전달이 되거나, function에서 함수를 return하거나 변수에 함수를 할당할 수 있다는 것이다.
그럼 first-class functions을 선언하는 방법이 따로 있는걸까?
-> What is first class function in Python
파이썬의 모든 functions은 first-class functions라고 한다. 그러니까 모든 함수는 argument로 전달 가능하고 함수에서 return될 수 있으며 변수에 할당될 수 있다.
def square(x):
return x*x
f = square(5)
print(square)
> <function square at 0x7fc8d5dd2e18>
print(f)
> 25
함수 호출시 square()
과 square
은 다르다. ()
은 함수를 실행하라는 의미이다. ()
없이 함수이름만 적으면 함수 그 자체를 의미하며, 여기서 first-class function의 개념이 적용되는데 f = square
로 함수를 f
에 할당할 수 있다.
def square(x):
return x*x
def my_map(func, arg_list):
result = []
for i in arg_list:
result.append(func(i))
return result
squares = my_map(square, [1,2,3,4,5])
print(squares)
> [1, 4, 9, 16, 25]
my_map
함수는 func
파라메터로 함수들을 전달받을 수 있다. 전달된 함수들은 for문 안에서 적용이 된 후 result에 값으로 추가된다. my_map
에서 함수 인자는 ()
을 포함하지 않아야한다는 것을 명심하자.
일반적으로 우리가 string이나 숫자를 arguments로 전달했을 때와 마찬가지로 어느 함수든지 argument로 전달이 가능하다.
만약 square
함수 말고 cube
라는 함수를 다음과 같이 새로 선언했다고 하자.
def cube(x):
return x*x*x
이 cube
함수 또한 func
로 전달될 수 있다. 단, my_map
함수보다 먼저 선언되어야 한다.
cubes = my_map(cube, [1,2,3,4,5])
print(cubes)
> [1, 8, 27, 64, 125]
def logger(msg):
def log_message():
print('Log:', msg)
return log_message
log_hi = logger('Hi!')
log_hi()
> Log: Hi!
logger함수는 log_message함수를 return한다. 하지만 여기서 잘 살펴보면 log_message()가 아닌 log_message를 return하고 있으므로 함수 그자체를 의미하는 것이지 함수를 실행하라는 것이 아니다.
log_hi = logger('Hi!')
를 하면 log_hi는 log_message를 가르키게 되고 log_hi가 log_message 함수 그 자체가 된다. log_hi()
를 해주어야 비로소 log_message함수가 실행되는 것이다. 이때 처음에 logger함수에서 받아왔던 msg를 log_message 함수 내에서 사용할 수 있는데 이것을 closure라고 한다.
왜 함수에서 함수를 return하는게 유용할까? 다음의 예시를 살펴보자.
def html_tag(tag):
def wrap_text(msg):
print('<{0}>{1}</0>'.format(tag, msg))
return wrap_text
print_h1 = html_tag('h1')
print_h1('Test Headline!')
print_h1('Another Headline!')
> <h1>Test Headline!</h1>
<h1>Another Headline!</h1>
print_p = html_tag('p')
print_p('Test Paragraph!')
> <p>Test Paragraph!</p>
아까 살펴봤던 것과 비슷하게 print_h1 = html_tag('h1')
을 하면 tag에는 h1이 저장되고 print_h1은 wrap_test 그 자체가 된다.(return할때 함수 뒤에 ()
가 붙지 않았으므로)
html_tag
에서 넣어준 text는 바꾸지 않으면서 print_h1
에 Test Headline를 argument로 넣을수도 있고 Another Headline이라는 argument를 넣을수도 있게된다.