First-class function

16. First-class function

First-class 함수: 함수 자체를 인자로 다른 함수에 전달, 다른 함수의 결과값으로 리턴, 함수를 변수에 할당할 수 있는 함수

  • 사실 파이썬에서는 모든 것이 객체!
  • 파이썬 함수도 객체로 되어 있어서, 기본 함수 기능 이외 객체와 같은 활용이 가능 (파이썬의 함수들은 First-class 함수로 사용 가능)

  • 지금까지 배운 언어의 맥락과는 뿌리가 다른 사고 - 함수형 프로그래밍에서부터 고안된 기법

16.1. 다른 변수에 함수 할당 가능

def calc_square(digit):
    return digit * digit
calc_square(2)
# 1. func1 이라는 변수에 함수를 할당 가능
func1 = calc_square
print (calc_square)
func1(2)

16.2. 함수가 할당된 변수는 동일한 함수처럼 활용 가능

# 2. func1 이라는 변수는 calc_square 함수를 가리키고, calc_square 와 마찬가지로 인자도 넣어서 결과도 얻을 수 있음 (완전 calc_square와 동일)
print (func1)
func1(2)
class MyClass:
    def my_class(self):
        print ('안녕')
        pass

object1 = MyClass()
my_class1 = object1.my_class
my_class1()

16.3. 함수를 다른 함수에 인자로 넣을 수도 있음

def calc_square(digit):
    return digit * digit

def calc_plus(digit):
    return digit + digit

def calc_quad(digit):
    return digit * digit * digit * digit
def list_square(function, digit_list):
    result = list()
    for digit in digit_list:
        result.append(function(digit)) 
    print (result)
num_list = [1, 2, 3, 4, 5]
list_square(calc_square, num_list)
list_square(calc_plus, num_list)
list_square(calc_quad, num_list)
num_list_square

16.4. 함수의 결과값으로 함수를 리턴할 수도 있음1

def logger(msg):
    message = msg
    def msg_creator():    # <--- 함수 안에 함수를 만들 수도 있음
        print ('[HIGH LEVEL]: ', message)
    return msg_creator
log1 = logger('Dave Log-in')
print(log1)
log1()
복습
1. 함수 안에 선언된 변수를 칭하는 용어는?
2. 함수 안에 선언된 변수 값이 유지되는 기간은?
3. 위 코드에서 log1() 결과값에서 특이한 점은?

아예 logger 함수를 통째로 삭제해도 log1() 함수는 logger 함수 안에 있는 msg_creator 함수와 msg 값을 유지

del logger
log1()

16.5. 함수의 결과값으로 함수를 리턴할 수도 있음2

def html_creator(tag):
    def text_wrapper(msg):
        print ('<{0}>{1}<{0}>'.format(tag, msg))
    return text_wrapper
h1_html_creator = html_creator('h1') #1
print (h1_html_creator)
h1_html_creator('H1 태그는 타이틀을 표시하는 태그입니다.')
p_html_creator = html_creator('p')
p_html_creator('P 태그는 문단을 표시하는 태그입니다.')
생각해보기
위와 같이 출력되는 이유를 생각해봅니다.
초간단 연습2
스트링으로 된 문자열이 주어지면, 정해진 목차 기호로 나열해주는 First-class 함수를 만들어보세요
예: 
func1 = index_creator('-')
func1(list_data)

출력:
* ....
* ....
* ....
def list_creator(tag):
    def text_wrapper(msg):
        print ('{0} {1}'.format(tag, msg))
    return text_wrapper

data_list_minus = list_creator('-')
data_list_minus('안녕')

data_list_mul = list_creator('*')
data_list_mul('안녕')

data_list_x = list_creator('X')
data_list_x('안녕')

도전 과제
위에서 만든 First-class 함수로 네이버 실시간 키워드를 리스트로 출력해보세요
import requests
from bs4 import BeautifulSoup

res = requests.get('https://www.naver.com/')
soup = BeautifulSoup(res.content, 'html.parser')
# a 태그이면서 href 속성 값이 특정한 값을 갖는 경우 탐색
link_title = soup.select("#PM_ID_ct > div.header > div.section_navbar > div.area_hotkeyword.PM_CL_realtimeKeyword_base > div.ah_roll.PM_CL_realtimeKeyword_rolling_base > div > ul > li")
for num in range(len(link_title)):
    # link_title 은 리스트 타입으로 개별 태그셋을 저장합니다.
    # print(type(link_title))
    # 각 태그셋은 string이 아니라 BeautifulSoup의 element.Tag 라는 객체입니다.
    # print(type(link_title[0]))
    # 그래서 각 태그셋에 다시 find(), find_all() 과 같은 BeautifulSoup 메서드를 사용할 수 있음을 확인할 수 있습니다.
    link_title_each = link_title[num].find_all('span')
    data_list_minus(link_title_each[1].get_text())