第 4 章 文本和字節(jié)序列
人類使用文本林说, 計算機使用字節(jié)序列。
第 5 章 一等函數
前言:
在 Python 中屯伞, 函數是一等對象腿箩。 編程語言理論家把“一等對象”定義為滿足下述條件的程序實體:
1、在運行時創(chuàng)建
2劣摇、能賦值給變量或數據結構中的元素
3珠移、能作為參數傳給函數
4、能作為函數的返回結果
5.1 把函數視作對象
map、 filter和reduce的現(xiàn)代替代品
函數式語言通常會提供 map剑梳、 filter 和 reduce 三個高階函數( 有時使用不同的名稱) 唆貌。 在 Python 3 中, map 和 filter 還是內置函數垢乙, 但是由于引入了列表推導和生成器表達式锨咙, 它們變得沒那么重要了。 列表推導或生成器表達式具有 map 和 filter 兩個函數的功能追逮, 而且更易于閱讀酪刀, 如示例:
>>> list(map(fact, range(6))) ? # fact是一個提前定義好的階乘函數n!
[1, 1, 2, 6, 24, 120]
>>> [fact(n) for n in range(6)] ?
[1, 1, 2, 6, 24, 120]
>>> list(map(factorial, filter(lambda n: n % 2, range(6)))) ?
[1, 6, 120]
>>> [factorial(n) for n in range(6) if n % 2] ?
[1, 6, 120]
>>>
5.3 匿名函數
Python 簡單的句法限制了 lambda 函數的定義體只能使用純表達
式。 換句話說钮孵, lambda 函數的定義體中不能賦值骂倘, 也不能使用 while
和 try 等 Python 語句,在參數列表中最適合使用匿名函數。
>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
>>> sorted(fruits, key=lambda word: word[::-1])
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
除了作為參數傳給高階函數之外巴席, Python 很少使用匿名函數历涝。 由于句法上的限制, 非平凡的 lambda 表達式要么難以閱讀漾唉, 要么無法寫出.
5.4 可調用對象
除了用戶定義的函數荧库, 調用運算符( 即 ()) 還可以應用到其他對象
上。 如果想判斷對象能否調用赵刑, 可以使用內置的 callable()
函數分衫。
Python 數據模型文檔列出了 7 種可調用對象:
- 用戶定義的函數:使用 def 語句或 lambda 表達式創(chuàng)建。
- 內置函數
- 內置方法
- 方法
- 類
- 類的實例
- 生成器函數
5.5 用戶定義的可調用類型
不僅 Python 函數是真正的對象般此, 任何 Python 對象都可以表現(xiàn)得像函
數蚪战。 為此, 只需實現(xiàn)實例方法 __call__
铐懊。
import random
class BingoCage:
def __init__(self, items):
self._items = list(items)
random.shuffle(self._items) # 隨機洗牌
def pick(self):
try: # list = [1,2,3]; list.pop()結果為3邀桑,再輸入list,結果為[1,2]
return self._items.pop()
except ImportError:
raise LookupError('pick from empty BigoCate')
def __call__(self):
return self.pick() # 實現(xiàn)bingo.pick() 的快捷方式是 bingo()
bingo = BingoCage(range(3))
print( bingo.pick() ) # 結果:0 or 1 or 2
print( bingo() ) # 上方已經定義了隨機洗牌 ; ??bingo已經是實例,我們還可以 實例(),表現(xiàn)的像函數
print( callable(bingo) ) # True
5.6 函數內省
除了__doc__
科乎, 函數對象還有很多屬性概漱。 使用 dir 函數可以探知
factorial
(已定義的一個函數) 具有下述屬性:
>>> dir(factorial)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
'__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__get__', '__getattribute__', '__globals__',
'__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__',
'__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
>>>
列出常規(guī)對象沒有而函數有的屬性
>>> class C: pass # ?
>>> obj = C() # ?
>>> def func(): pass # ?
>>> sorted(set(dir(func)) - set(dir(obj))) # ?
['__annotations__', '__call__', '__closure__', '__code__', '__defaults__',
'__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']
>>>
? 創(chuàng)建一個空的用戶定義的類。
? 創(chuàng)建一個實例喜喂。
? 創(chuàng)建一個空函數瓤摧。
? 計算差集, 然后排序玉吁, 得到類的實例沒有而函數有的屬性列表照弥。
5.7 從定位參數到僅限關鍵字參數
*args
參數會被存入一個元組
**kwargs
參數會被存入一個字典
5.11 本章小結
本章的目標是探討 Python 函數的一等本性。 這意味著进副, 我們可以把函數賦值給變量这揣、 傳給其他函數悔常、 存儲在數據結構中, 以及訪問函數的屬性给赞, 供框架和一些工具使用机打。 高階函數是函數式編程的重要組成部分,即使現(xiàn)在不像以前那樣經常使用 map片迅、 filter 和 reduce 函數了残邀, 但是還有列表推導( 以及類似的結構, 如生成器表達式) 以及 sum柑蛇、 all和 any 等內置的歸約函數芥挣。 Python 中常用的高階函數有內置函數sorted
、 min
耻台、 max
和 functools. partial
空免。
Python 有 7 種可調用對象, 從 lambda 表達式創(chuàng)建的簡單函數到實現(xiàn)__call__
方法的類實例盆耽。 這些可調用對象都能通過內置的callable()
函數檢測蹋砚。 每一種可調用對象都支持使用相同的豐富句法聲明形式參數, 包括僅限關鍵字參數和注解——二者都是 Python 3 引入的新特性摄杂。
Python 函數及其注解有豐富的屬性坝咐, 在 inspect
模塊的幫助下, 可以讀取它們匙姜。 例如畅厢, Signature.bind
方法使用靈活的規(guī)則把實參綁定到形參上冯痢, 這與 Python 使用的規(guī)則一樣氮昧。
最后, 本章介紹了 operator
模塊中的一些函數浦楣, 以及
functools.partial
函數袖肥, 有了這些函數, 函數式編程就不太需要功
能有限的 lambda
表達式了振劳。
雜談
Python 是函數式語言嗎椎组?
編程語言“范式”已近末日, 它們是舊時代的遺留物历恐, 令人厭煩寸癌。 既然現(xiàn)代語言的設計者對范式不屑一顧, 那么我們的課程為什么要像奴隸一樣對其言聽計從弱贼?
在那篇論文中蒸苇, 下面這一段點名提到了 Python:
對 Python、 Ruby 或 Perl 這些語言還要了解什么呢吮旅? 它們的設
計者沒有耐心去精確實現(xiàn)林奈層次結構溪烤; 設計者按照自己的意
愿從別處借鑒特性, 創(chuàng)建出完全無視過往概念的大雜燴。
Krishnamurthi 指出檬嘀, 不要試圖把語言歸為某一類槽驶; 相反, 把它們視
作特性的聚合更有用鸳兽。
為 Python 提供一等函數打開了函數式編程的大門掂铐, 不過這并不是
Guido 的目的。 他在“Origins of Python's Functional Features”一文
( http://python-history.blogspot.com/2009/04/origins-of-pythonsfunctional-features.html) 中說贸铜, map堡纬、 filter 和 reduce 的最初目的是為 Python 增加 lambda 表達式。 這些特性都由 Amrit Prem 貢獻蒿秦, 添加在 1994 年發(fā)布的 Python 1.0 中( 參見 CPython 源碼中的
Misc/HISTORY 文件烤镐,https://hg.python.org/cpython/file/default/Misc/HISTORY) 。