附錄B 裝飾器
附 錄 B
裝 飾 器
python 程式設計
python 簡要講義
國立中央大學數學系 吳維漢
附錄B 裝飾器
python 函式為第一類物件 (一)
2
 python 函式為第一類物件(first-class object)
 函式可當成物件使用
 函式可當成參數傳入另一個函式使用
def square( fn , a , b ) :
return [ fn(x) for x in range(a,b+1) ]
# 將 abs 傳入 square 函式使用
print( square( abs , -2 , 2 ) ) # 印出 [2, 1, 0, 1, 2]
def square( a , b ) :
return [ x*x for x in range(a,b+1) ]
# foo 即是 square
foo = square
print( foo( -2 , 2 ) ) # 印出 [4, 1, 0, 1, 4]
附錄B 裝飾器
python 函式為第一類物件 (二)
3
 函式可回傳函式
 函式內可定義函式
# 回傳設定係數後的一元二次方程式函式
def spoly( a , b , c ) :
return lambda x : a*x*x + b*x + c
# fn = x**2 + 2*x + 1
fn = spoly(1,2,1)
for x in range(3) :
print( x , fn(x) ) # 印出:0 1,1 4,2 9 共三列
def fsum( f , g ) :
# fn 為兩函式之和
def fn(x) : return f(x) + g(x)
return fn
def square(x) : return x * x
def cubic(x) : return x * x * x
# h(x) = square(x) + cubic(x)
h = fsum( square , cubic )
for x in range(0,3) :
print( x , h(x) ) # 印出:0 0,1 2,2 12 共三列
附錄B 裝飾器
python 函式為第一類物件 (三)
4
 函式可存入其它資料型別中
# 使用上例的函式
fns = [ square , cubic ] # fns 串列內存兩函式
for x in range(0,3) :
print( x , end=" " )
for fn in fns :
print( fn(x) , end=“ ” ) # 印出:0 0 0,1 1 1,2 4 8 三列
print()
附錄B 裝飾器
函式裝飾器 (一)
5
 函式裝飾器:以函式當為裝飾器
 用來包裝函式的函式,擴充原有函式功能
1. 版本一
def square(x) : return x*x
def cubic(x) : return x*x*x
# 計算在 x 在 [a,b] 之間的函數數值和
def fsum_over( fn , a , b ) :
return sum( [ fn(x) for x in range(a,b+1) ] )
# 分別將 square 與 cubic 函式當成參數傳入
print( fsum_over( square , -2 , 2 ) ) # 印出:10
print( fsum_over( cubic , -2 , 2 ) ) # 印出:0
 以上 square、cubic、fsum_over 三函式各自獨立
附錄B 裝飾器
函式裝飾器 (二)
6
2. 版本二
def square(x) : return x*x
def cubic(x) : return x*x*x
# decorate 函式名稱,非保留字
def decorate( fn ) :
def fsum_over( a , b ) :
return sum( [ fn(x) for x in range(a,b+1) ] )
return fsum_over
# decorate 回傳的 fsum_over 被當成新的 square,square 函式不再是
原有 square
square = decorate(square)
# 這裡的 square 事實上是 fsum_over 函式,square 變成雙參數函式
print( square(-2,2) ) # 印出:10
 以上接收的 square 函式是原有函式 square 與 fsum_over 的合體函式,等同
square 函式經過 decorate 裝飾器函式的處理後「融合」了兩個函式功能,造成
square 函式產生質變,由單參數函式變為雙參數函式。
附錄B 裝飾器
函式裝飾器 (三)
7
def rangesum( fn ) :
def fsum_over( a , b ) :
return sum( [ fn(x) for x in range(a,b+1) ] )
return fsum_over
def square(x) : return x*x
square = rangesum(square)
def cubic(x) : return x*x*x
cubic = rangesum(cubic)
可分別簡化為:
def rangesum( fn ) :
def fsum_over( a , b ) :
return sum( [ fn(x) for x in range(a,b+1) ] )
return fsum_over
@rangesum
def square(x) : return x*x
@rangesum
def cubic(x) : return x*x*x
 裝飾器簡化語法:
附錄B 裝飾器
類別裝飾器 (一)
8
 類別裝飾器:以類別當為裝飾器
 函式運算子:__call__
class RangeSum :
def __init__( self , fn ) :
self.fn = fn
# 函式運算子:讓物件可用函式方式執行實例方法
def __call__( self , a , b ) :
return sum( [ self.fn(x) for x in range(a,b+1) ] )
# 輸入 abs 絕對值函式
foo = RangeSum( abs )
# 以下兩者相同,都印出 12
print( foo.__call__(-3,3) )
print( foo(-3,3) )
 foo 為 RangeSum 物件,foo(-3,3) 等同 foo.__call__(-3,3)
附錄B 裝飾器
類別裝飾器 (二)
9
 使用類別裝飾器:需定義類別的函式運算子
@RangeSum
def square( x ) : return x*x
@RangeSum
def cubic( x ) : return x*x*x
# 分別執行 RangeSum 的函式運算子
print( square(-2,2) ) # 印出:10
print( cubic(-2,2) ) # 印出:0
 定義類別裝飾器時需連同設定類別的函式運算子

Appendix B 教學

  • 1.
    附錄B 裝飾器 附 錄B 裝 飾 器 python 程式設計 python 簡要講義 國立中央大學數學系 吳維漢
  • 2.
    附錄B 裝飾器 python 函式為第一類物件(一) 2  python 函式為第一類物件(first-class object)  函式可當成物件使用  函式可當成參數傳入另一個函式使用 def square( fn , a , b ) : return [ fn(x) for x in range(a,b+1) ] # 將 abs 傳入 square 函式使用 print( square( abs , -2 , 2 ) ) # 印出 [2, 1, 0, 1, 2] def square( a , b ) : return [ x*x for x in range(a,b+1) ] # foo 即是 square foo = square print( foo( -2 , 2 ) ) # 印出 [4, 1, 0, 1, 4]
  • 3.
    附錄B 裝飾器 python 函式為第一類物件(二) 3  函式可回傳函式  函式內可定義函式 # 回傳設定係數後的一元二次方程式函式 def spoly( a , b , c ) : return lambda x : a*x*x + b*x + c # fn = x**2 + 2*x + 1 fn = spoly(1,2,1) for x in range(3) : print( x , fn(x) ) # 印出:0 1,1 4,2 9 共三列 def fsum( f , g ) : # fn 為兩函式之和 def fn(x) : return f(x) + g(x) return fn def square(x) : return x * x def cubic(x) : return x * x * x # h(x) = square(x) + cubic(x) h = fsum( square , cubic ) for x in range(0,3) : print( x , h(x) ) # 印出:0 0,1 2,2 12 共三列
  • 4.
    附錄B 裝飾器 python 函式為第一類物件(三) 4  函式可存入其它資料型別中 # 使用上例的函式 fns = [ square , cubic ] # fns 串列內存兩函式 for x in range(0,3) : print( x , end=" " ) for fn in fns : print( fn(x) , end=“ ” ) # 印出:0 0 0,1 1 1,2 4 8 三列 print()
  • 5.
    附錄B 裝飾器 函式裝飾器 (一) 5 函式裝飾器:以函式當為裝飾器  用來包裝函式的函式,擴充原有函式功能 1. 版本一 def square(x) : return x*x def cubic(x) : return x*x*x # 計算在 x 在 [a,b] 之間的函數數值和 def fsum_over( fn , a , b ) : return sum( [ fn(x) for x in range(a,b+1) ] ) # 分別將 square 與 cubic 函式當成參數傳入 print( fsum_over( square , -2 , 2 ) ) # 印出:10 print( fsum_over( cubic , -2 , 2 ) ) # 印出:0  以上 square、cubic、fsum_over 三函式各自獨立
  • 6.
    附錄B 裝飾器 函式裝飾器 (二) 6 2.版本二 def square(x) : return x*x def cubic(x) : return x*x*x # decorate 函式名稱,非保留字 def decorate( fn ) : def fsum_over( a , b ) : return sum( [ fn(x) for x in range(a,b+1) ] ) return fsum_over # decorate 回傳的 fsum_over 被當成新的 square,square 函式不再是 原有 square square = decorate(square) # 這裡的 square 事實上是 fsum_over 函式,square 變成雙參數函式 print( square(-2,2) ) # 印出:10  以上接收的 square 函式是原有函式 square 與 fsum_over 的合體函式,等同 square 函式經過 decorate 裝飾器函式的處理後「融合」了兩個函式功能,造成 square 函式產生質變,由單參數函式變為雙參數函式。
  • 7.
    附錄B 裝飾器 函式裝飾器 (三) 7 defrangesum( fn ) : def fsum_over( a , b ) : return sum( [ fn(x) for x in range(a,b+1) ] ) return fsum_over def square(x) : return x*x square = rangesum(square) def cubic(x) : return x*x*x cubic = rangesum(cubic) 可分別簡化為: def rangesum( fn ) : def fsum_over( a , b ) : return sum( [ fn(x) for x in range(a,b+1) ] ) return fsum_over @rangesum def square(x) : return x*x @rangesum def cubic(x) : return x*x*x  裝飾器簡化語法:
  • 8.
    附錄B 裝飾器 類別裝飾器 (一) 8 類別裝飾器:以類別當為裝飾器  函式運算子:__call__ class RangeSum : def __init__( self , fn ) : self.fn = fn # 函式運算子:讓物件可用函式方式執行實例方法 def __call__( self , a , b ) : return sum( [ self.fn(x) for x in range(a,b+1) ] ) # 輸入 abs 絕對值函式 foo = RangeSum( abs ) # 以下兩者相同,都印出 12 print( foo.__call__(-3,3) ) print( foo(-3,3) )  foo 為 RangeSum 物件,foo(-3,3) 等同 foo.__call__(-3,3)
  • 9.
    附錄B 裝飾器 類別裝飾器 (二) 9 使用類別裝飾器:需定義類別的函式運算子 @RangeSum def square( x ) : return x*x @RangeSum def cubic( x ) : return x*x*x # 分別執行 RangeSum 的函式運算子 print( square(-2,2) ) # 印出:10 print( cubic(-2,2) ) # 印出:0  定義類別裝飾器時需連同設定類別的函式運算子