Effective Python – 例26 定義function decorators使用functools.wraps

python有簡單的語法來使用function decorators,但有可能造成一些不想要的副作用,例如可能會把help給覆蓋。

def trace(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f'{func.__name__}({args!r}, {kwargs!r}) -> {result!r}')
        return result
    return wrapper

@trace
def fibonacci(n):
    """Return the n-th Fibonacci number"""
    if n in (0, 1):
        return n
    return (fibonacci(n - 2) + fibonacci(n -1))

# @trace 等於是 fibonacci = trace(fibonacci)

fibonacci(4)

help(fibonacci)

import pickle
pickle.dumps(fibonacci)
fibonacci((0,), {}) -> 0
fibonacci((1,), {}) -> 1
fibonacci((2,), {}) -> 1
fibonacci((1,), {}) -> 1
fibonacci((0,), {}) -> 0
fibonacci((1,), {}) -> 1
fibonacci((2,), {}) -> 1
fibonacci((3,), {}) -> 2
fibonacci((4,), {}) -> 3
Help on function wrapper in module __main__:

wrapper(*args, **kwargs)

Traceback (most recent call last):
  File "C:/Users/hans/Desktop/item 26.py", line 22, in 
    pickle.dumps(fibonacci)
AttributeError: Can't pickle local object 'trace..wrapper'

在wrapper function加上wraps可以修好help跟pickle

from functools import wraps

def trace(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f'{func.__name__}({args!r}, {kwargs!r}) -> {result!r}')
        return result
    return wrapper

help(fibonacci)
print(pickle.dumps(fibonacci))
Help on function fibonacci in module __main__:

fibonacci(n)
    Return the n-th Fibonacci number

b'\x80\x04\x95\x1a\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\tfibonacci\x94\x93\x94.'

發表留言

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料