python函数可以作为容器对象吗_正确理解Python函数是第一类对象
正確理解 Python函數(shù),能夠幫助我們更好地理解 Python 裝飾器、匿名函數(shù)(lambda)、函數(shù)式編程等高階技術(shù)。
函數(shù)(Function)作為程序語言中不可或缺的一部分,太稀松平常了。但函數(shù)作為第一類對(duì)象(First-Class Object)卻是 Python 函數(shù)的一大特性。那到底什么是第一類對(duì)象呢?
函數(shù)是對(duì)象
在 Python 中萬物皆為對(duì)象,函數(shù)也不例外,函數(shù)作為對(duì)象可以賦值給一個(gè)變量、可以作為元素添加到集合對(duì)象中、可作為參數(shù)值傳遞給其它函數(shù),還可以當(dāng)做函數(shù)的返回值,這些特性就是第一類對(duì)象所特有的。
先來看一個(gè)簡(jiǎn)單的例子>>>?def?foo(text):...?????return?len(text)...>>>?foo("zen?of?python")13
這是一個(gè)再簡(jiǎn)單不過的函數(shù),用于計(jì)算參數(shù) text 的長度,調(diào)用函數(shù)就是函數(shù)名后面跟一個(gè)括號(hào),再附帶一個(gè)參數(shù),返回值是一個(gè)整數(shù)。
函數(shù)身為一個(gè)對(duì)象,擁有對(duì)象模型的三個(gè)通用屬性:id、類型、和值。>>>?id(foo)4361313816>>>?type(foo)>>>?foo
作為對(duì)象,函數(shù)可以賦值給一個(gè)變量>>>?bar?=?foo
賦值給另外一個(gè)變量時(shí),函數(shù)并不會(huì)被調(diào)用,僅僅是在函數(shù)對(duì)象上綁定一個(gè)新的名字而已。>>>?bar("zen?of?python")13>>>
同理,你還可以把該函數(shù)賦值給更多的變量,唯一變化的是該函數(shù)對(duì)象的引用計(jì)數(shù)不斷地增加,本質(zhì)上這些變量最終指向的都是同一個(gè)函數(shù)對(duì)象。>>>?a?=?foo
>>>?b?=?foo
>>>?c?=?bar
>>>?a?is?b?is?c
True
函數(shù)可以存儲(chǔ)在容器
容器對(duì)象(list、dict、set等)中可以存放任何對(duì)象,包括整數(shù)、字符串,函數(shù)也可以作存放到容器對(duì)象中,例如>>>?funcs?=?[foo,?str,?len]
>>>?funcs
[,?,?]
>>>?for?f?in?funcs:
...?????print(f("hello"))
...
5
hello
5
>>>
foo 是我們自定義的函數(shù),str 和 len 是兩個(gè)內(nèi)置函數(shù)。for 循環(huán)逐個(gè)地迭代出列表中的每個(gè)元素時(shí),函數(shù)對(duì)象賦值給了 f 變量,調(diào)用 f(“hello”) 與 調(diào)用 foo(“hello”) 本質(zhì)是一樣的效果,每次 f 都重新指向一個(gè)新的函數(shù)對(duì)象。當(dāng)然,你也可以使用列表的索引定位到元素來調(diào)用函數(shù)。>>>?funcs[0]("Python之禪")#?等效于?foo("Python之禪")8
函數(shù)可以作為參數(shù)
函數(shù)還可以作為參數(shù)值傳遞給另外一個(gè)函數(shù),例如:>>>?def?show(func):...?????size?=?func("python?之禪")?#?等效于?foo("Python之禪")?...?????print?("length?of?string?is?:?%s"?%?size)...>>>?show(foo)length?of?string?is?:?9
函數(shù)可以作為返回值
函數(shù)作為另外一個(gè)函數(shù)的返回值,例如:>>>?def?nick():
...?????return?foo
>>>?nick
>>>?a?=?nick()
>>>?a
>>>?a("python")
6
還可以簡(jiǎn)寫為>>>?nick()("python")
6
函數(shù)接受一個(gè)或多個(gè)函數(shù)作為輸入或者函數(shù)輸出(返回)的值是函數(shù)時(shí),我們稱這樣的函數(shù)為高階函數(shù),比如上面的?show?和nick?都屬于高階函數(shù)。
Python內(nèi)置函數(shù)中,典型的高階函數(shù)是?map?函數(shù),map 接受一個(gè)函數(shù)和一個(gè)迭代對(duì)象作為參數(shù),調(diào)用 map 時(shí),依次迭代把迭代對(duì)象的元素作為參數(shù)調(diào)用該函數(shù)。>>>?map(foo,?["the","zen","of","python"])>>>?lens?=?map(foo,?["the","zen","of","python"])>>>?list(lens)[3,?3,?2,?6]
map?函數(shù)的作用相當(dāng)于:>>>?[foo(i)?for?i?in?["the","zen","of","python"]][3,?3,?2,?6]
只不過 map 的運(yùn)行效率更快一點(diǎn)。
函數(shù)可以嵌套
Python還允許函數(shù)中定義函數(shù),這種函數(shù)叫嵌套函數(shù)。>>>?def?get_length(text):...?????def?clean(t):???????????#?2...?????????return?t[1:]...?????new_text?=?clean(text)??#?1...?????return?len(new_text)...>>>?get_length("python")5>>>
這個(gè)函數(shù)的目的是去除字符串的第一個(gè)字符后再計(jì)算它的長度,盡管函數(shù)本身的意義不大,但能足夠說明嵌套函數(shù)。get_length?調(diào)用時(shí),先執(zhí)行1處代碼,發(fā)現(xiàn)有調(diào)用?clean?函數(shù),于是接著執(zhí)行2中的代碼,把返回值賦值給了?new_text?,再繼續(xù)執(zhí)行后續(xù)代碼。>>>?clean("python")Traceback?(most?recent?call?last):
File?"",?line?1,?in?NameError:?name?'clean'?is?not?defined
函數(shù)中里面嵌套的函數(shù)不能在函數(shù)外面訪問,只能是在函數(shù)內(nèi)部使用,超出了外部函數(shù)的做用域就無效了。
實(shí)現(xiàn)了 __call__ 的類也可以作為函數(shù)
對(duì)于一個(gè)自定義的類,如果實(shí)現(xiàn)了 __call__ 方法,那么該類的實(shí)例對(duì)象的行為就是一個(gè)函數(shù),是一個(gè)可以被調(diào)用(callable)的對(duì)象。例如:class?Add:
def?__init__(self,?n):
self.n?=?n
def?__call__(self,?x):
return?self.n?+?x>>>?add?=?Add(1)>>>?add(4)>>>?5
執(zhí)行 add(4) 相當(dāng)于調(diào)用 Add._call__(add, 4),self 就是實(shí)例對(duì)象 add,self.n 等于 1,所以返回值為 1+4add(4)
||
Add(1)(4)
||
Add.__call__(add,?4)
確定對(duì)象是否為可調(diào)用對(duì)象可以用內(nèi)置函數(shù)callable來判斷。>>>?callable(foo)True>>>?callable(1)False>>>?callable(int)True
總結(jié)
Python中包含函數(shù)在內(nèi)的一切皆為對(duì)象,函數(shù)作為第一類對(duì)象,支持賦值給變量,作為參數(shù)傳遞給其它函數(shù),作為其它函數(shù)的返回值,支持函數(shù)的嵌套,實(shí)現(xiàn)了__call__方法的類實(shí)例對(duì)象也可以當(dāng)做函數(shù)被調(diào)用。
總結(jié)
以上是生活随笔為你收集整理的python函数可以作为容器对象吗_正确理解Python函数是第一类对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Optimal Milking
- 下一篇: java map取第一个元素_Java