Higher-Order Function #1

정은경·2020년 5월 3일

1. 학습목표

2. 학습내용

# 일급함수의 개념
# 파이썬에서는 모든 것을 객체로 취급한다
# 함수형 프로그래밍과 관련!

# 일급함수(일급객체)의 특징들
# 파이썸 함수 특징
# 1. 런타임 초기화
# 2. 변수 등에 할당 가능
# 3. 함수의 인수로 함수를 전달 가능
# 4. 함수의 결과로 함수를 반환 가능


# 함수 객체 예제
def factorial(n):
    '''Factorail Function -> n:int'''
    if n == 1:
        return 1
    return n * factorial(n-1)

class A:
    pass

# print('EX1-1 -', factorial(5))
# EX1-1 - 120
# print('EX1-2 -', factorial.__doc__)
# EX1-2 - Factorail Function -> n:int
# print('EX1-3 -', type(factorial), type(A))
# EX1-3 - <class 'function'> <class 'type'>
# print('EX1-4 -', dir(factorial))
"""
EX1-4 - ['__annotations__', '__call__', '__class__', '__closure__', '__code__', 
'__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', 
'__ge__', '__get__', '__getattribute__', 
'__globals__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', 
'__kwdefaults__', 
'__le__', '__lt__', '__module__', '__name__', 
'__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__']
"""
# print('EX1-5 -', dir(A))
"""
EX1-5 - ['__class__', 
'__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', 
'__ge__', '__getattribute__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', 
'__le__', '__lt__', '__module__', 
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__']
"""

# print('EX1-5 -', set(dir(factorial))-set(dir(A)))
"""
EX1-5 - {'__get__', '__globals__', '__qualname__', '__call__', 
'__code__', '__closure__', '__defaults__', '__kwdefaults__', '__name__', '__annotations__'}
"""

# print('EX1-6 -', factorial.__name__)
# EX1-6 - factorial
# print('EX1-7 -', factorial.__code__)
"""
EX1-7 - <code object factorial at 0x1029de6f0, 
file "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 14>
"""


# 변수 할당
var_func = factorial
# print('EX2-1 -', var_func)
# EX2-1 - <function factorial at 0x10176c1e0>
# print('EX2-2 -', var_func(5))
# EX2-2 - 120
# print('EX2-3 -', map(var_func, range(1,6)))
# EX2-3 - <map object at 0x102201978>
# print('EX2-4 -', list(map(var_func, range(1, 6))))
# EX2-4 - [1, 2, 6, 24, 120]



# 함수 인수 전달 및 함수로 결과 반환 -> 고위 함수(Higher-order Function)
# print('EX3-0', list(map(var_func, range(1,6))))
# EX3-0 [1, 2, 6, 24, 120]
# print('EX3-1', list(map(var_func, filter(lambda x: x % 2, range(1,6)))))
# EX3-1 [1, 6, 120]
# print('EX3-2', [var_func(i) for i in range(1,6) if i % 2])
# EX3-2 [1, 6, 120]


# reduce() # 권장하는 방법은 아님
from functools import reduce
from operator import add

# print('EX3-3 -', reduce(add, range(1,11)))
# EX3-3 - 55
# print('EX3-4 -', sum(range(1,11)))
# EX3-4 - 55


# 익명함수(lambda)
# 가급적 주석을 사용
# 가독성을 위해서 가급적 일반 함수를 사용할 것
# 일반 함수 형태로 리팩토링 권장
# print('EX3-5 -', reduce(lambda x, t: x+t, range(1,11)))
# EX3-5 - 55


# Callable : 호출 연산자 -> 메소드 형태로 호출 가능한지 확인
import random
# 로또 추첨 클래스 선언
class LottoGame:
    def __init__(self):
        self._balls = [n for n in range(1,46)]

    def pick(self):
        random.shuffle(self._balls)
        return sorted([random.choice(self._balls) for n in range(6)])

    def __call__(self, *args, **kwargs): # "__call__" 메소드 정의로 callable 해짐!
        return self.pick()

# 객체 생성
game = LottoGame()

# 게임 실행
# print('EX4-1 -', game.pick())
# EX4-1 - [7, 10, 21, 34, 37, 40]

# 호출 가능 확인
# print('EX4-2 -', callable(str), callable(list), callable(factorial), callable(3.14))
# EX4-2 - True True True False
# print('EX4-3 -', game())
# EX4-3 - [5, 10, 18, 24, 30, 36]
# print('EX4-4 -', callable(game))
# EX4-4 - True


# 다양한 매개변수 입력(*args, **kwargs)
def args_test(name, *contents, point=None, **attrs):
    return '<args_test>-> ({}) ({}) ({}) ({})'.format(name, contents, point, attrs)

# print('EX5-1 -', args_test('test1'))
# X5-1 - <args_test>-> (test1) (()) (None) ({})
# print('EX5-2 -', args_test('test1', 'test2'))
# EX5-2 - <args_test>-> (test1) (('test2',)) (None) ({})
# print('EX5-3 -', args_test('test1', 'test2', 'test3'))
# EX5-3 - <args_test>-> (test1) (('test2', 'test3')) (None) ({})
# print('EX5-4 -', args_test('test1', 'test2', 'test3', id='admin'))
# EX5-4 - <args_test>-> (test1) (('test2', 'test3')) (None) ({'id': 'admin'})
# print('EX5-5 -', args_test('test1', 'test2', 'test3', id='admin', point=7))
# EX5-5 - <args_test>-> (test1) (('test2', 'test3')) (7) ({'id': 'admin'})
# print('EX5-6 -', args_test('test1', 'test2', 'test3', id='admin', point=7, password=1234))
# EX5-6 - <args_test>-> (test1) (('test2', 'test3')) (7) ({'id': 'admin', 'password': 1234})


# 함수 Signaturres
# 함수 인자에 대한 정보를 표시해 줄 수 있는 클래스 형태의 메소드
# inspect 패키지 자주 사용함..!
from inspect import signature

sg = signature(args_test)
# print('EX6-1 -', sg)
# EX6-1 - (name, *contents, point=None, **attrs)
# print('EX6-2 -', sg.parameters)
# EX6-2 - OrderedDict([('name', <Parameter "name">), ('contents', <Parameter "*contents">), ('point', <Parameter "point=None">), ('attrs', <Parameter "**attrs">)])


# 모든 정보 출력
for name, param in sg.parameters.items():
    # print('EX6-3 -', name, param.kind, param.default)
    pass
"""
EX6-3 - name POSITIONAL_OR_KEYWORD <class 'inspect._empty'>
EX6-3 - contents VAR_POSITIONAL <class 'inspect._empty'>
EX6-3 - point KEYWORD_ONLY None
EX6-3 - attrs VAR_KEYWORD <class 'inspect._empty'>
"""


# Partial 사용법: 인수를 고정해서 새로운 함수를 리턴한
# 주로 특정 인수 고정 후 콜백 함수에 사용
# 하나 이상의 인수가 이미 할당된(채워진) 함수의 새 버전 반환
# 함수의 새 객체 타입은 이전 함수 자체를 기술하고 있다

from operator import mul
from functools import partial

# print('EX7-1 -', mul(10,100))
# EX7-1 - 1000

# 인수 고정
five = partial(mul, 5)

# 고정 추가
six = partial(five, 6)

# print('EX7-2 -', five(2))
# EX7-2 - 10
# print('EX7-3 -', six())
# EX7-3 - 30
# print('EX7-4 -', [five(i) for i in range(1,11)])
# EX7-4 - [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
# print('EX7-5 -', list(map(five, range(1,11))))
# EX7-5 - [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]

3. 느낀 점

profile
#의식의흐름 #순간순간 #생각의스냅샷

0개의 댓글