在開始前,會需要先具備Scope的基本觀念:Python變數範圍 – Scope
Closure
在函數執行時,會建立一個local scope,當函數執行完,這個local scope並不會被清除——而且只要你知道怎麼再次訪問,它都會確保你訪問得到其中的變數
Decorator
decorator的概念即是透過closure的特性,將傳入的函式經裝飾後回傳一介面,如以下範例:
經裝飾後回傳都會是同一個介面,這樣會導致debug的困難:
1 2 3 4 5 6 7 8 9 10 |
@counter def add(a, b): return a+b @counter def mul(a, b): return a*b adder = add() multer = mul() adder.__name__ == multer.__name__ == 'inner' # True |
可以用built-in的wraps來處理,wraps是decorator,一樣要把函式傳入
1 2 3 4 5 6 7 |
from functools import wraps def counter(fn): @warps(fn) def inner(*args, **kwargs): # do someting return inner |
decorator可以堆疊,以下這個範例其實只是做了auth(log(f))
這樣的處理
1 2 3 4 5 6 7 8 9 10 11 |
def auth(func): # do something def log(func): # do something # check authorization first @auth @log def f(): # do something |
Decorator Factory
至於decorator乍看之下可以傳額外的參數,其實只是再多封裝了一層decorator:
Decorator Class(用於decorator的類別)
此外,我們也能透過callable物件來製作decorator
Class Decorator (用來裝飾類別的decorator)
Python的monkey paching特性(在程式的runtime能隨意更改物件屬性),我們也可以透過decorator來裝飾類別
其他範例:
functools.totoal_ordering
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def total_ordering(cls): """Class decorator that fills in missing ordering methods""" # Find user-defined comparisons (not those inherited from object). roots = [op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)] if not roots: raise ValueError('must define at least one ordering operation: < > <= >=') root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__ for opname, opfunc in _convert[root]: if opname not in roots: opfunc.__name__ = opname setattr(cls, opname, opfunc) return cls |