โมดูล functools ให้ utilities สำหรับ Higher-Order Functions - ฟังก์ชันที่รับ/คืนฟังก์ชันอื่น
partial() - Freeze Arguments
สร้างฟังก์ชันใหม่โดยล็อกอาร์กิวเมนต์บางส่วน
>> import functools
# int(x, base=10) → base=2 version
>>> binint = functools.partial(int, base=2)
>>> binint('1001')
9
# User function
>>> def myfunc(a, b):
... return a * b
>>> part = functools.partial(myfunc, b=10)
>>> part(10)
100
partialmethod() - สำหรับ Method Definition
>> class Cell:
... def __init__(self):
... self.alive = False
... @functools.partialmethod
... def set_state(self, state, value=True):
... self.alive = value if state == 'alive' else False
...
>>> c = Cell()
>>> c.set_state('alive')
>>> c.alive
True
cmp_to_key() - แปลง Comparison Function เป็น Key Function
Python 3 ลบ cmp parameter ออกจาก sort() ใช้ key แทน แต่ legacy code ใช้ cmp function
>> from functools import cmp_to_key
>>> class Test:
... def __init__(self, x):
... self.x = x
... def __str__(self):
... return str(self.x)
>>> def cmp_func(a, b):
... if a.x >= b.x: return 1
... return -1
>>> mykey = cmp_to_key(cmp_func)
>>> sorted([Test(3), Test(1), Test(2)], key=mykey)
[, , ]
reduce() - Fold/Accumulate
นำฟังก์ชัน binary ไป apply สะสมทีละตัว (left to right)
>> import functools
>>> def mult(x, y):
... return x * y
>>> functools.reduce(mult, range(1, 11))
3628800 # 10!
# กับ initial value
>>> functools.reduce(mult, [2, 3, 4], 5)
120 # 5 * 2 * 3 * 4
Decorators อื่นๆ ใน functools
| Decorator | ใช้สำหรับ |
|---|---|
@lru_cache | Memoization (cache ผลลัพธ์) |
@total_ordering | เติม __lt__, __le__, __gt__, __ge__ จาก __eq__ + หนึ่งใน ordering |
@wraps | Copy metadata (__name__, __doc__, etc.) ใน decorator |
@singledispatch | Function overloading ตาม type ของ arg แรก |
ตัวอย่าง @lru_cache
>> @functools.lru_cache(maxsize=128)
... def fib(n):
... if n < 2: return n
... return fib(n-1) + fib(n-2)
>>> fib(100) # เร็วมากเพราะ cache
354224848179261915075
>>> fib.cache_info()
CacheInfo(hits=98, misses=101, maxsize=128, currsize=101)
@wraps สำคัญสำหรับ Decorators
>> def my_decorator(func):
... @functools.wraps(func)
... def wrapper(*args, **kwargs):
... print("Before")
... return func(*args, **kwargs)
... return wrapper
>>> @my_decorator
... def hello():
... """Say hello"""
... print("Hello")
>>> hello.__name__
'hello'
>>> hello.__doc__
'Say hello'