Python裝飾器的一點解讀_貨運

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

  版權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須註明原文網址

  http://www.cnblogs.com/Colin-Cai/p/12977127.html 

  作者:窗戶

  QQ/微信:6679072

  E-mail:6679072@qq.com

  理論上,函數是一等公民(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

  終於看到,函數功能已被擴充。

  這個裝飾器還可以裝飾別的函數,比如乘積、統計等。

 

  從而,裝飾器就是這樣一個算子,一般用來改造函數的輸入或輸出,避免重複寫代碼。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式