1. 程式人生 > >【函數】04、裝飾器

【函數】04、裝飾器

裝飾器

一、高階函數

python中函數是一等對象(first class);函數也是對象,並且它可以像普通對象一樣復制、作為參數、作為返回值。

返回函數或者參數是函數的函數就是高階函數,也被稱為函數式編程

In [23]: def counter(base):
    ...:     def inc(x=1):
    ...:         nonlocal base
    ...:         base += x
    ...:         return base
    ...:     return inc          # 返回一個函數
    ...: 

In [24]: inc = counter(3)

In [25]: inc
Out[25]: <function __main__.counter.<locals>.inc>

In [26]: inc()
Out[26]: 4

In [27]: inc()
Out[27]: 5


內置函數sorted()的實現:

In [48]: def sort(it, cmp=lambda a, b: a<b):
    ...:     ret = []
    ...:     for x in it:
    ...:         for i, e in enumerate(ret):
    ...:             if cmp(x, e):
    ...:                 ret.insert(i, x)
    ...:                 break
    ...:         else:
    ...:             ret.append(x)
    ...:     return ret
    ...: 

In [49]: sort([1, 3, 5, 2, 4, ])
Out[49]: [1, 2, 3, 4, 5]

In [50]: sort([1, 3, 5, 2, 4, ], lambda a, b: a>b)
Out[50]: [5, 4, 3, 2, 1]


總結:

函數作為返回值常用於閉包的場景:需要封裝一些變量

函數作為參數常用於大多數邏輯固定,少部分邏輯不固定的場景

函數作為參數,返回值也為是函數:常用於作為參數的函數在執行前後需要一些額外的操作(增加功能)

In [77]: def add(x, y):
    ...:     return x + y
    ...: 

In [78]: add.__name__
Out[78]: ‘add‘


In [80]: def logger(fn):
    ...:     def wrap(*args, **kwargs):
    ...:         print(‘call {}‘.format(fn.__name__))
    ...:         ret = fn(*args, **kwargs)
    ...:         print(‘{} called‘.format(fn.__name__))
    ...:         return ret
    ...:     return wrap
    ...: 

In [81]: loged_add = logger(add)

In [82]: loged_add(3, 5)
call add
add called
Out[82]: 8

簡單、優雅一點:

In [90]: def add(x, y):
    ...:     return x + y
    ...: 

In [91]: def logger(fn):
    ...:     def wrap(*args, **kwargs):
    ...:         print(‘call {}‘.format(fn.__name__))
    ...:         ret = fn(*args, **kwargs)
    ...:         print(‘{} called‘.format(fn.__name__))
    ...:         return ret
    ...:     return wrap
    ...: 

In [92]: add = logger(add)    # add變量名被重新賦值定義,賦值是先執行右邊的部分

In [93]: add(3, 4)
call add
add called
Out[93]: 7

更簡單、優雅:

In [102]: def logger(fn):
     ...:     def wrap(*args, **kwargs):
     ...:         print(‘call {}‘.format(fn.__name__))
     ...:         ret = fn(*args, **kwargs)
     ...:         print(‘{} called‘.format(fn.__name__))
     ...:         return ret
     ...:     return wrap
     ...: 

In [103]: @logger # @這是裝飾器的語法糖,相當於 add=logger(add)=wrp
     ...: def add(x, y):
     ...:     return x + y
     ...: 

In [104]: add(1, 2)
call add
add called
Out[104]: 3

這是logger就是裝飾器了


二、裝飾器

1、裝飾器

函數的參數是一個函數,返回值也是一個函數,就可以作為裝飾器




【函數】04、裝飾器