while (1): study();
Part3. 객체로서의 함수 본문
5. 일급 함수
일급 객체
1. 런타임에 생성 가능
2. 데이터 구조체의 변수나 요소에 할당 가능
3. 함수 인수로 전달 가능
4. 함수 결과로 반환 가능
고위 함수(higher-order function): 함수를 결과로 반환하는 함수
map(), filter() -> 컴프리헨션의 등장으로 중요성 저하
reduce()
all(): 모든 iterable이 참이면 true
any(): iterable이 하나라도 참이면 true
람다: 최대한 안 쓰는게 좋음 (가독성)
매개변수
*을 기점으로 위치 매개변수와 키워드 매개변수를 나눔
def f(a, *, b): # b는 기본값이 지정되지 않은 키워드 매개변수
return a, b
* 매개변수 추출: inspect 이용
from inspect import signature
sig = signature(func)
for name, param in sig.parameters.items():
print(param.kind, ':', name, '=', param.default)
함수 애너테이션
전혀 처리하지 않음, 인터프리터에 아무 의미 없음
독스트링과 같이 주석을 달아주는 것뿐
함수형 프로그래밍 모듈
1) operator: reduce 등에 쓸 수 있는 연산함수 지원
itemgetter(), attrgetter()
from collections import namedtuple
from operator import attrgetter
LatLong = namedtuple('LatLong', 'lat long')
Metropolis = namedtuple('Metropolis', 'name cc pop coord')
metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long)) for name, cc, pop, (lat, long) in metro_data]
name_lat = attrgetter('name', 'coord.lat')
for city in sorted(metro_areas, key=attrgetter('coord.lat')):
print(name_lat(city))
2) functools
partial(): 함수 인수를 부분적으로 고정
from operator import mul, floordiv
from functools import partial
triple = partial(floordiv, 3)
list(map(triple, range(1, 10)))
6. 일급 함수 디자인 패턴
전략
콘텍스트: 일부 계산을 전략 컴포넌트에 위임
전략: 여러 전략이 구현된 공통 인터페이스
* abc.abstractmethod를 상속(플라이웨이트) or 함수를 전달(내부 상태없이 처리만 하는 경우)
* 최적 전략 선택
# 1. globals(): 전역 심볼 테이블 반환
[globals()[name] for name in globals()]
# 2. inspect.getmembers
[func for name, func in inspect.getmembers(module, inspect.is_function)]
명령
연산 실행 객체(Invoker)와 구현 객체(Receiver)를 분리
7. 함수 데커레이터와 클로저
데커레이터
1) 데커레이터는 데커레이트된 함수를 다른 함수로 대체
2) 임포트 타임에 실행(먼저 대체된 함수를 만들어놓음)
변수 범위 규칙
지역 변수 -> 전역 변수 순으로 찾으나
전역 변수와 같은 이름의 지역 변수가 컨텍스트 안에 선언되어 있으면 무조건 지역 변수로 판단
전역 변수로 만들고 싶으면 global 사용
클로저
def make_averager():
series = [] # 자유변수
def averager(new_value): # 클로저
series.append(new_value)
total = sum(series)
return total / len(series)
return averager
함수 본체에서 정의하지 않고 참조하는 비전역 변수를 포함한 확장 범위를 가진 함수
함수를 정의할 때 존재하던 자유변수에 대한 바인딩을 유지하는 함수
함수가 다른 함수 안에 정의된 경우만 발생
자유변수에 새로운 값을 할당할때는 nonlocal 선언 필요 (+= 등 사용 시 지역변수로 판단해버리기 때문)
def make_averager():
count, total = 0, 0
def averager(new_value):
nonlocal count, total
count += 1
total += new_value
return total / count
return averager
표준 라이브러리 데커레이터
functools.lru_cache(): 메모이제이션
@functools.lru_cache(maxsize=128)
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 2) + fibonacci(n - 1)
if __name__ == '__main__':
print(fibonacci(6))
functools.singledispatch(): 첫번째 인수의 자료형에 따른 서로 다른 방식의 연산
import html
import numbers
from collections import abc
@functools.singledispatch
def htmlize(obj):
content = html.escape(repr(obj))
return '<pre>{}<pre>'.format(content)
@htmlize.register(str)
def _(text):
content = html.escape(text).replace('\n', '<br>\n')
return '<p>0<p>'.format(content)
@htmlize.register(numbers.Integral)
def _(n):
return '<pre>{0} (0x{0:x})</pre>'.format(n)
@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
inner = '</li>\n</li>'.join(htmlize(item) for item in seq)
return '<ul>\n<li>' + inner + '</li>\n</ul>'
매개변수화된 데커레이터
인수를 받아 데커레이터를 반환하는 데커레이터 팩토리를 만들고, 데커레이트될 함수에 데커레이터 팩토리 적용
registry = set()
def register(active=True):
def decorate(func):
print('running register(active=%s) -> decorate(%s)' % (active, func))
if active:
registry.add(func)
else:
registry.discard(func)
return func
return decorate
@register(active=False)
def f1():
print('running f1()')
@register(active=True)
def f2():
print('running f2()')
def f3():
print('running f3()')
'독서' 카테고리의 다른 글
Part5. 제어 흐름 (0) | 2021.12.08 |
---|---|
Part4. 객체지향 상용구 (0) | 2021.12.05 |
Part2. 데이터 구조체 (0) | 2021.12.05 |
Part1. 들어가며 (0) | 2021.12.05 |
Ch8. 어텐션 (0) | 2021.08.01 |