Python3 中作為一等對(duì)象的函數(shù)解析
Python3 函數(shù)
函數(shù)是組織好的,可重復(fù)使用的,用來(lái)實(shí)現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段。
函數(shù)能提高應(yīng)用的模塊性,和代碼的重復(fù)利用率。你已經(jīng)知道Python提供了許多內(nèi)建函數(shù),比如print()。但你也可以自己創(chuàng)建函數(shù),這被叫做用戶自定義函數(shù)。
在 Python 語(yǔ)言中,函數(shù)與整數(shù)、字符串、字典等基本數(shù)據(jù)類型一樣,都是 一等對(duì)象 。所謂一等對(duì)象,即滿足如下三個(gè)條件:
- 在運(yùn)行時(shí)創(chuàng)建
- 能賦值給變量
- 能作為函數(shù)的參數(shù)或返回值
以下 IDLE 中的代碼即在運(yùn)行時(shí)創(chuàng)建了函數(shù) factorial :
>>> def factorial(n): ... '''calculates n!''' ... return 1 if n < 2 else n * factorial(n-1) ... >>> factorial(5) 120 >>> factorial.__doc__ 'calculates n!' >>> type(factorial) <class 'function'> >>> fact = factorial >>> fact <function factorial at 0x7f55bc771c10> >>> fact(5) 120 >>> list(map(fact, range(10))) [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
從輸出中可以看出, factorial 是 function 類的實(shí)例對(duì)象, __doc__ 是 factorial 對(duì)象眾多屬性中的一個(gè)。
可以把 factorial 函數(shù)賦值給變量 fact ,通過(guò) fact 變量調(diào)用 factorial 函數(shù)。還可以把 factorial 作為參數(shù)傳遞給 map 函數(shù)。
這些行為表現(xiàn)了函數(shù)作為一等對(duì)象的特性。
一、高階函數(shù)
接受函數(shù)作為參數(shù),或者把函數(shù)作為返回值的函數(shù)即為 高階函數(shù) 。
如內(nèi)置用于排序的 sorted 函數(shù),它的 key 參數(shù)用于傳入一個(gè)函數(shù),在需要排序的每個(gè)元素上執(zhí)行特定的操作。如根據(jù)單詞長(zhǎng)度對(duì)多個(gè)字符串進(jìn)行排序:
>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana'] >>> sorted(fruits, key=len) ['fig', 'apple', 'cherry', 'banana', 'raspberry', 'strawberry']
任何單參數(shù)的函數(shù)都可以作為 key 的值傳給 sorted 函數(shù),如把單詞反向拼寫作為排序條件:
>>> def reverse(word): ... return word[::-1] ... >>> reverse('test') 'tset' >>> sorted(fruits, key=reverse) ['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
map、filter 與 reduce
函數(shù)式編程語(yǔ)言通常會(huì)提供 map 、 filter 和 reduce 三個(gè)高階函數(shù)或者實(shí)現(xiàn)了類似功能的函數(shù)。Python3 中的列表推導(dǎo)和生成器即具有 map 和 filter 函數(shù)的功能。
參考如下示例:
>>> def fact(n): ... return 1 if n < 2 else n * fact(n-1) ... >>> list(map(fact, range(6))) [1, 1, 2, 6, 24, 120] >>> [fact(n) for n in range(6)] [1, 1, 2, 6, 24, 120] >>> list(map(fact, filter(lambda n: n % 2, range(6)))) [1, 6, 120] >>> [fact(n) for n in range(6) if n % 2] [1, 6, 120]
通過(guò)列表推導(dǎo)可以完成與 map 或 filter 函數(shù)類似的工作,且可讀性更高,也避免了使用 lambda 表達(dá)式。
reduce 在 Python2 中是內(nèi)置函數(shù),但在 Python3 中被移到了 functools 模塊中。 reduce 可以把某個(gè)操作連續(xù)地應(yīng)用到某個(gè)序列上,累計(jì)所有的結(jié)果,把產(chǎn)生的一系列值規(guī)約成一個(gè)值。因此常用于求和計(jì)算,但內(nèi)置的 sum 函數(shù)在可讀性和性能方面更優(yōu)。
>>> from functools import reduce >>> from operator import add >>> reduce(add, range(101)) 5050 >>> sum(range(101)) 5050
二、匿名函數(shù)
可以使用 lambda 關(guān)鍵字在 Python 表達(dá)式內(nèi)創(chuàng)建匿名函數(shù)。
在函數(shù)的參數(shù)列表中最適合使用匿名函數(shù)。如前面的根據(jù)字符串反序后的結(jié)果對(duì)單詞列表進(jìn)行排序,可以使用 lambda 匿名函數(shù)替代傳入 sorted 的 reverse 函數(shù):
>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana'] >>> sorted(fruits, key=lambda word: word[::-1]) ['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
lambda 表達(dá)式 lambda words: words[::-1] 即等同于之前的 reverse 函數(shù):
def reverse(word): return word[::-1]
除了作為參數(shù)傳給某個(gè)高階函數(shù)外,Python 很少使用匿名函數(shù)。
三、可調(diào)用對(duì)象
除了用戶自定義的函數(shù),其他可調(diào)用對(duì)象也可以使用調(diào)用運(yùn)算符(即 () )。
Python 的數(shù)據(jù)模型中共包含 7 種可調(diào)用對(duì)象:
- 用戶自定義函數(shù):使用 def 語(yǔ)句或 lambda 表達(dá)式創(chuàng)建的函數(shù)
- 內(nèi)置函數(shù):由 C 語(yǔ)言(CPython)實(shí)現(xiàn)的函數(shù),如 len 或 time.strftime 等
- 內(nèi)置方法:使用 C 語(yǔ)言實(shí)現(xiàn)的方法,如 dict.get
- 方法:在類的定義體中定義的函數(shù)
- 類:類在調(diào)用時(shí)會(huì)使用 __new__ 方法創(chuàng)建實(shí)例,然后運(yùn)行 __init__ 初始化實(shí)例,最后將實(shí)例返回給調(diào)用方。調(diào)用類相當(dāng)于調(diào)用函數(shù)。
- 類的實(shí)例:如果類的定義中實(shí)現(xiàn)了 __call__ 方法,則其實(shí)例可以作為函數(shù)調(diào)用
- 生成器:使用 yield 關(guān)鍵字的函數(shù)或方法??梢苑祷厣善鲗?duì)象。
使用內(nèi)置的 callable() 函數(shù)可以確認(rèn)對(duì)象是否可調(diào)用。
任何 Python 對(duì)象都可以表現(xiàn)得像函數(shù),只需實(shí)現(xiàn)該實(shí)例的 __call__ 方法。
如下面的 bingocall.py ,從列表中隨機(jī)取出一個(gè)元素:
import random class BingoCage: def __init__(self, items): self._items = list(items) random.shuffle(self._items) def pick(self): try: return self._items.pop() except IndexError: raise LookupError('pick from empty BingoCage') def __call__(self): return self.pick() bingo = BingoCage(range(50)) print(bingo.pick()) # => 38 print(bingo()) # => 22 print(callable(bingo)) # => True
bingo 是 BingoCage 類的一個(gè)實(shí)例,由于 BingoCage 類中實(shí)現(xiàn)了 __call__ 方法,則 bingo 對(duì)象是可調(diào)用的( bingo() )。
四、支持函數(shù)式編程的模塊
operator
在函數(shù)式編程中,經(jīng)常需要將算術(shù)運(yùn)算符當(dāng)作函數(shù)使用。如不使用遞歸計(jì)算階乘。
使用 reduce 和 lambda 表達(dá)式計(jì)算階乘:
>>> from functools import reduce >>> def fact(n): ... return reduce(lambda a, b: a*b, range(1, n+1)) ... >>> fact(5) 120
Python 中的 operator 為多個(gè)運(yùn)算符提供了對(duì)應(yīng)的函數(shù),可以避免寫 lambda a, b: a*b 這種匿名函數(shù)。
使用 reduce 和 operator.mul 計(jì)算階乘:
>>> from operator import mul >>> from functools import reduce >>> def fact(n): ... return reduce(mul, range(1, n+1)) ... >>> fact(5) 120
operator 模塊中還有一類 itemgetter 和 attrgetter 函數(shù),可以替代從序列中取出元素或讀取屬性的 lambda 表達(dá)式。
如根據(jù)元組中的第二個(gè)元素對(duì)多個(gè)元組進(jìn)行排序:
>>> metro_data = [ ... ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)), ... ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)), ... ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)), ... ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)), ... ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)), ... ] >>> from operator import itemgetter >>> for city in sorted(metro_data, key=itemgetter(1)): ... print(city) ... ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)) ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)) ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)) ('New York-Newark', 'US', 20.104, (40.808611, -74.020386))
如果把多個(gè)參數(shù)傳遞給 itemgetter ,則該函數(shù)會(huì)返回由提取的值構(gòu)成的元組:
>>> cc_name = itemgetter(1, 0) >>> for city in metro_data: ... print(cc_name(city)) ... ('JP', 'Tokyo') ('IN', 'Delhi NCR') ('MX', 'Mexico City') ('US', 'New York-Newark') ('BR', 'Sao Paulo')
attrgetter 與 itemgetter 作用類似,可以根據(jù)名稱提取對(duì)象的屬性。
operator 模塊中還有一個(gè) methodcaller 函數(shù),可以用來(lái)在某個(gè)對(duì)象上調(diào)用由參數(shù)指定的方法。
>>> from operator import methodcaller >>> s = 'The time has come' >>> upcase = methodcaller('upper') >>> upcase(s) 'THE TIME HAS COME' >>> hiphenate = methodcaller('replace', ' ', '-') >>> hiphenate(s) 'The-time-has-come' functools.partial
高階函數(shù) functools.partial 用來(lái) 部分應(yīng)用 某個(gè)函數(shù)。即基于某個(gè)函數(shù)創(chuàng)建一個(gè)新的可調(diào)用對(duì)象,并把原函數(shù)的某些參數(shù)固定。
如使用 partial 把一個(gè)接受雙參數(shù)的函數(shù)改編成單參數(shù)的可調(diào)用對(duì)象:
>>> from operator import mul >>> from functools import partial >>> triple = partial(mul, 3) >>> triple(7) 21 >>> list(map(triple, range(1, 10))) [3, 6, 9, 12, 15, 18, 21, 24, 27]
partial() 函數(shù)返回一個(gè) functools.partial 對(duì)象,該對(duì)象提供對(duì)原函數(shù)的訪問(wèn)和固定原函數(shù)參數(shù)的行為。
>>> def greeting(words, name): ... return f'{words}, {name}!' ... >>> from functools import partial >>> greeting2 = partial(greeting, name='skitar') >>> greeting2("what's up") "what's up, skitar!" >>> greeting2 functools.partial(<function greeting at 0x7f70f31788b0>, name='skitar')
總結(jié)
以上所述是小編給大家介紹的Python3 中作為一等對(duì)象的函數(shù)解析,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
Python爬蟲實(shí)現(xiàn)“盜取”微信好友信息的方法分析
這篇文章主要介紹了Python爬蟲實(shí)現(xiàn)“盜取”微信好友信息的方法,結(jié)合實(shí)例形式分析了Python針對(duì)微信數(shù)據(jù)信息爬取的相關(guān)操作技巧,需要的朋友可以參考下2019-09-09django2.2安裝錯(cuò)誤最全的解決方案(小結(jié))
這篇文章主要介紹了django2.2安裝錯(cuò)誤最全的解決方案(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09python游戲?qū)崙?zhàn)項(xiàng)目之俄羅斯方塊的魅力
遲早一定會(huì)掛掉的俄羅斯方塊,為什么至今仍是世界游戲之王?它是怎么編寫的?本文將給大家詳細(xì)的介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值2021-09-09TensorFlow加載模型時(shí)出錯(cuò)的解決方式
今天小編就為大家分享一篇TensorFlow加載模型時(shí)出錯(cuò)的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02Python實(shí)現(xiàn)強(qiáng)制復(fù)制粘貼的示例詳解
下個(gè)文檔還要馬內(nèi)?還好我會(huì)Python,本文就來(lái)教大家來(lái)一手如何利用Python實(shí)現(xiàn)強(qiáng)制復(fù)制粘貼。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12python實(shí)現(xiàn)Decorator模式實(shí)例代碼
這篇文章主要介紹了python實(shí)現(xiàn)Decorator模式實(shí)例代碼,簡(jiǎn)單介紹了裝飾器的含義和語(yǔ)法,分享了相關(guān)實(shí)例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02零基礎(chǔ)學(xué)習(xí)python偏函數(shù)語(yǔ)法的推導(dǎo)方法步驟
這篇文章主要介紹了零基礎(chǔ)學(xué)習(xí)python偏函數(shù)語(yǔ)法的推導(dǎo)方法步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06詳解Python logging調(diào)用Logger.info方法的處理過(guò)程
這篇文章主要介紹了詳解Python logging調(diào)用Logger.info方法的處理過(guò)程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02Python openpyxl 遍歷所有sheet 查找特定字符串的方法
今天小編就為大家分享一篇Python openpyxl 遍歷所有sheet 查找特定字符串的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12