[Python] 일급 객체로서의 함수
일급 객체
- 런타임에 생성할 수 있다.
- 데이터 구조체의 변수나 요소에 할당할 수 있다.
- 함수 인수로 전달할 수 있다.
- 함수 결과로 반환할 수 있다.
함수를 객체 처럼 다루기
- 함수를 변수에 할당하고, 이 변수명을 통해 함수를 호출한다.
- 함수를 다른 함수의 인수로 전달할 수도 있다.
고위 함수
함수를 인수로 받거나, 실행 결과로 함수를 반환하는 함수map()
, sorted()
, filter()
, reduce()
, apply()
...
map()
, filter()
, reduce()
의 최신 대안
지능형 리스트와 제너레이터 표현식이 소개된 후에는 이 함수들의 중요성이 떨어졌음
map()
과 filter()
는 제너레이터를 반환하므로, 제너레이터 표현식이 이 함수들을 직접 대체한다.
>>> list(map(factorial, range(6)))
[1, 1, 2, 6, 24, 120]
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> list(map(factorial, filter(lambda n: n % 2, range(6))))
[1, 6, 120]
>>> [factorial(n) for n in range(6) if n % 2]
[1, 6, 120]
reduce()
함수는 functools
모듈로 떨어져 나왔다.
합계 계산용으로 reduce()
쓰려면 그냥 sum()
을 쓰자reduce(add, range(100))
-> sum(range(100))
익명 함수
lambda
키워드는 파이썬 표현식 안에 익명 함수를 생성한다.
다만 람다 본체에서는 while
, try
등의 파이썬 문장 사용 불가, =
할당문도 불가.
- 주로 인수 목록 안에서 유용하게 활용
아홉 가지 콜러블 객체
호출 가능한 객체인지 알아보려면 callable()
사용해보기
사용자 정의 함수
def 문이나 lambda 표현식으로 생성
내장 함수len()
이나 time.strftime()
처럼 C엉너로 구현된 함수
내장 메서드dict.get()
처럼 C 언어로 구현된 메서드
메서드
클래스 본체에 정의된 함수
클래스
호출될 때 자신의 __new__()
메서드를 실행해 인스턴스 생성, __init__()
으로 초기화, 최종적으로 인스턴스 반환
파이썬에는 new
연산자가 없어 클래스 호출은 함수 호출과 동일하다.
클래스 인스턴스
클래스가 __call__()
메서드를 구현하면서 이 클래스의 인스턴스는 함수로서 호출될 수 있다.
제너레이터 함수yield
키워드를 사용하는 함수나 메서드, 호출되면 제너레이터 객체 반환
네이티브 코루틴 함수async def
로 정의된 함수나 메서드, 호출되면 코루틴 객체 반환
비동기 제너레이터 함수async def
로 정의되고, 본체 안에 yield
문이 있는 함수나 메서드, 호출되면 async for
문에 사용할 비동기 제너레이터 반환
사용자 정의 callable 객체
__call__()
메서드를 정의한 클래스의 인스턴스
class Greeter:
def __init__(self, name):
self.name = name
def __call__(self, message):
return f"{message}, {self.name}!"
greet = Greeter("Kyu")
print(greet("Hello")) # Hello, Kyu!
- Greeter 클래스는 call() 메서드를 정의했기 때문에 인스턴스가 함수처럼 호출 가능
- greet("Hello")는 내부적으로 greet.call("Hello")를 호출하는 것과 같음
- 지피티한테 물어본거
\
상태 저장형 콜러블
함수처럼 쓰지만 내부 상태를 기억함(객체여서 가능!)
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
counter = Counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
- 객체가 호출될 때마다 내부의 count 값을 증가시켜서 상태를 유지함.
데코레이터 스타일 콜러블
함수에 기능을 덧붙이는 객체형 데코레이터
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Before function call")
result = self.func(*args, **kwargs)
print("After function call")
return result
@MyDecorator
def say_hello():
print("Hello!")
say_hello()
result
Before function call
Hello!
After function call
- @MyDecorator는 say_hello = MyDecorator(say_hello)와 같음.
- MyDecorator 인스턴스가 콜러블이니까 say_hello()를 호출할 수 있음.
- 중간에 로깅, 실행 시간 측정, 권한 체크 등을 넣을 수 있음
함수형 프로그래밍을 위한 패키지
operator 모듈
파이썬의 연산자를 함수처럼 사용할 수 있게 해주는 모듈
import operator
print(operator.add(1, 2)) # 3 → 1 + 2
print(operator.mul(3, 4)) # 12 → 3 * 4
print(operator.itemgetter(1)(['a', 'b', 'c'])) # 'b' → 리스트에서 index 1 추출
map()
,sorted()
,reduce()
같은 함수에서 간결하게 연산자 전달할 때 유용
functools 모듈
함수를 다루기 쉽게 만드는 고차 함수/데코레이터 유틸 모음
functools.partial
: 인자 고정해서 새 함수 생성>>> from operator import mul >>> from functools import partial >>> triple = partial(mul, 3) >>> triple(7) 21 >>> list(map(triple, range(1, 10))) [3, 6, 9, 12, 15, 18, 21, 24, 27]
References
- 『 전문가를 위한 파이썬(2판) 』, 루시아누 하말류, 한빛미디어, Part 1 - Chapter 7
- 네이티브 코루틴, 비동기 제너레이터가 궁금하다! 얼른 알고 싶다. 내가 캡스톤 프로젝트 할때 열심히 적용했던 코루틴, 비동기 제너레이터.. 나름 찾아보면서 적용했던 기억은 있는데.. 완전히 정리하고 싶다 머릿속에 쏘옥
- 상태 저장형 콜러블은 보자마자 리액트의
useState
가 생각이 났다. 프론트는 안 한지 너무 오래됐지만 반가웠다^^.... - 전에 대규모 웹 크롤러 성능 개선 목적으로 실행 시간 측정하고 싶어서 데코레이터를 도입한 적이 있다. 그때 너무 어려웠는데..ㅜㅜㅜ 데코레이터는 잘 알면 아주 유용할것같다.