著作權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖,如要轉貼,必須注明原文網址 http://www.cnblogs.com/Colin-Cai/p/12977127.html 作者:窗戶 QQ/微信:6679072 E-mail:[email protected]
理論上,函式是一等公民(first class function)的語言都可以使用函式式編程,從而利用算子(高階函式)來做裝飾器,
裝飾器一般是這樣一個算子,它接受一個函式作為引數,回傳另外一個函式,裝飾器,顧名思義,就是把一個函式“裝飾”一下,得到另外一個函式,為何要裝飾一下呢?目的一般是可能設計上需要對函式做一些改裝,比如原函式輸出結果需要再加工加工,或者原函式的輸入引數傳入不一樣,或者兩者兼有之,等等,
迭代是編程中常用的手段,它的計算方式表現為狀態的不斷變換,且狀態的變換具有唯一性,
比如我們使用Scheme來表示迭代,
;stat代表當前狀態,next代表狀態改變函式,final?代表判斷狀態是否終止 (define (iterate-orgin stat next final?) (if (final? stat) stat (iterate-orgin (next stat) next final?))) ;將next函式和final?函式封成一個函式 (define (iterate stat f-stat) (iterate-orgin stat (f-stat 'next) (f-stat 'final))) ;最終我們需要的迭代函式 (define (it f-stat) (lambda (stat) (iterate stat f-stat)))
以上構造出一個算子it,就是用來“裝飾”迭代的函式,
我們構造一個對list求和的迭代:
可以每次把list的前面兩個相加,比如對(1 2 3 4 5)求和,經過以下狀態:
(1 2 3 4 5)
(3 3 4 5)
(6 4 5)
(10 5)
(15)
15
得到最后結果15,
代碼可以如下:
(define (make-sum-func sym) (if (eq? sym 'next);next函式 (lambda (lst) (if (pair? lst) (if (null? (cdr lst)) (car lst) (cons (+ (car lst) (cadr lst)) (cddr lst))) lst)) (if (eq? sym 'final?);final?函式 (lambda (lst) (not (pair? lst))) '())))
然后測驗一下((it make-sum-func) '(1 2 3 4 5)),得到最后結果15,
上面兩個函式寫在一起,我們還可以再分離一下,
;定義一個打包函式 (define (wrap-next-final next final?) (lambda (sym) (if (eq? sym 'next) next (if (eq? sym 'final?) final? '())))) ;下面next和final?兩個函式可以分開寫 (define make-sum-next (lambda (lst) (if (pair? lst) (if (null? (cdr lst)) (car lst) (cons (+ (car lst) (cadr lst)) (cddr lst))) lst))) (define make-sum-final? (lambda (lst) (not (pair? lst)))) ;于是函式就可以下面這樣表示 (define make-sum-func (wrap-next-final make-sum-next make-sum-final?))
總而言之,裝飾器就是這樣一類算子,
Python也是這樣,只是Python提供了@這樣的語法,實際上是個語法糖,與其說是簡寫,倒是更像是個語法提醒這是一個裝飾器,
我們這次希望來顯示一下mysym,還是用求和,
先寫一個簡單的mysum函式用于求和:
def mysum(*args): ret = 0 for i in args: ret += i return ret
做一個算子,來擴充它的輸入引數:
這里需要用來判斷一個物件是否是可迭代物件,
from collections import Iterable
然后,如果判斷物件x是否是可迭代物件,只需要:
isinstance(x, Iterable)
算子如下:
from collections import Iterable def args_expan(f): def f2(*args): lst = [] for i in args: if isinstance(i, Iterable): lst.append(f(*i)) else: lst.append(i) return f(*lst) return f2
然后在mysum前添加裝飾器標志
@args_expan def mysum(*args): ret = 0 for i in args: ret += i return ret
測驗如下:
print(mysum(1,2,3,4,5)) print(mysum((1,2,3,4,5))) print(mysum([1,2,3,4,5])) print(mysum(range(1,6))) print(mysum(map(lambda x:x+1, range(5)))) print(mysum(filter(lambda x:x<6, range(10)))) #構造了一個生成器 def gen_range(a, b): while a < b: yield a a += 1 print(mysum(\ filter(lambda x:x<6, range(10)), \ 6, \ [7,8], \ (9, 10), \ map(lambda x:x+11, range(10)), \ gen_range(21,101)))
運行得到:
15
15
15
15
15
15
5050
終于看到,函式功能已被擴充,
這個裝飾器還可以裝飾別的函式,比如乘積、統計等,
從而,裝飾器就是這樣一個算子,一般用來改造函式的輸入或輸出,避免重復寫代碼,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/141166.html
標籤:Python
