# ===== CodeLab: python-functools =====
# 以下代码片段按文章出现顺序拼接, 共 7 段

# ----- 片段 1 (python) -----
def shout(text):
    return text.upper()

def whisper(text):
    return text.lower()

def speak(func, text):
    return func(text)

print(speak(shout, "hello"))    # HELLO
print(speak(whisper, "HELLO"))  # hello

# ----- 片段 2 (python) -----
double = lambda x: x * 2
print(double(21))          # 42

add = lambda a, b: a + b
print(add(3, 5))           # 8

# 等价于:
def double_def(x):
    return x * 2
print(double_def(21))

# ----- 片段 3 (python) -----
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])   # [2, 2, 2],不是 [0, 1, 2]!

# ----- 片段 4 (python) -----
from functools import reduce

nums = [1, 2, 3, 4, 5]

# map:把函数作用到每个元素上
doubled = list(map(lambda x: x * 2, nums))
print(doubled)                    # [2, 4, 6, 8, 10]

# filter:保留使函数返回真的元素
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)                      # [2, 4]

# reduce:从左到右累积,把序列归约成一个值
total = reduce(lambda a, b: a + b, nums, 0)
print(total)                      # 15

# ----- 片段 5 (python) -----
nums = [3, 1, 4, 1, 5, 9, 2, 6]

# 推导式替代 map
print([x * 2 for x in nums])

# 推导式替代 filter
print([x for x in nums if x % 2 == 0])

# sorted 的 key 接收函数:按长度、按末字母排序
words = ["banana", "apple", "cherry", "date"]
print(sorted(words, key=len))            # 按长度升序
print(sorted(words, key=lambda w: w[-1]))  # 按最后一个字母排序

# ----- 片段 6 (python) -----
from functools import partial

def power(base, exp):
    return base ** exp

square = partial(power, exp=2)
cube = partial(power, exp=3)

print(square(5))    # 25
print(cube(5))      # 125
print(power(5, 2))  # 原函数不受影响

# ----- 片段 7 (python) -----
from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(50))   # 12586269025,瞬间出结果
print(fib.cache_info())  # CacheInfo(hits=48, misses=51, ...)
