函數(shù)

轉(zhuǎn):https://foofish.net/function-is-first-class-object.html

在計算機(jī)中闺骚,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的,每當(dāng)進(jìn)入一個函數(shù)調(diào)用虫碉,棧就會加一層棧幀胸梆,每當(dāng)函數(shù)返回,棧就會減一層棧幀碰镜。由于棧的大小不是無限的,所以秽荤,遞歸調(diào)用的次數(shù)過多,會導(dǎo)致棧溢出王滤。

python 的函數(shù)是第一對象

正確理解 python 函數(shù),能夠幫我們更好地理解 裝飾器(@)第喳、匿名函數(shù)(lambda)與函數(shù)式編程等高階技術(shù)踱稍。

一、函數(shù)是對象

在 Python 中萬物皆為對象珠月,函數(shù)也不例外,函數(shù)作為對象可以賦值給一個變量驻谆、可以作為元素添加到集合對象中、可作為參數(shù)值傳遞給其它函數(shù)胜臊,還可以當(dāng)做函數(shù)的返回值伙判,這些特性就是第一類對象所特有的。
簡單的函數(shù):

>>> def foo(text):
...     return len(text)
... 
>>> foo('zen of python')
13

函數(shù) foo() 作為一個對象勒魔,擁有對象模型的三個通用屬性:id、類型冠绢、值:

>>> id(foo)
34515536
>>> type(foo)
<class 'function'>
>>> foo
<function foo at 0x020EAA50>

函數(shù)作為對象羊娃,可以賦值給另外一個變量:

>>> bar = foo
>>> bar
<function foo at 0x020EAA50>
>>> bar("zen of python")
13
>>> bar == foo
True

bar = foo 是因為他們指向一樣

圖片.png

賦值給另外一個變量時蕊玷,函數(shù)并不會被調(diào)用弥雹,僅僅是在函數(shù)對象上綁定一個新的名字而已(或新名字指向該函數(shù)),單純的起一個新名字不需要加括號和參數(shù)贸诚;

二、函數(shù)可以存儲在容器

容器對象(list酱固、dict、set等)中可以放任何對象龄减,包括證書、字符串希停。函數(shù)也可以放在容器對象中:

>>> funcs = [foo, str, len]
>>> funcs
[<function foo at 0x103f45e18>, <class 'str'>, <built-in function len>]
>>> for f in funcs:
...     print(f("hello"))
...
5
hello
5
>>>

foo 是我們自定義的函數(shù)署隘,str 和 len 是兩個內(nèi)置函數(shù)∥コ纾可以通過索引或列表遍歷來調(diào)用函數(shù):

[<function foo at 0x020EAA50>, <class 'str'>, <built-in function len>]
>>> funcs[0]('zen of python')
13

三、函數(shù)可以作為參數(shù)

函數(shù)還可以作為參數(shù)傳遞給另外一個函數(shù):

>>> def show(func):
...     size = func("zen of python")
...     print('length of string is : {}'.format(size))
...     
>>> show(foo)
length of string is : 13

四羞延、函數(shù)還可以作為返回值:

>>> def nick():
...     return foo
... 
>>> nick
<function nick at 0x020EA078>
>>> a = nick
>>> a
<function nick at 0x020EA078>
>>> a("python")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: nick() takes 0 positional arguments but 1 was given
>>> a = nick()
>>> a
<function foo at 0x020EAA50>
>>> a("python")
6

這里有個錯誤肴楷,見最后

還可以簡寫為:

>>> nick()("python")
6

函數(shù)接收一個或多個函數(shù)作為輸入或者函數(shù)輸出(返回)的值是函數(shù)時荠呐,我們稱這樣的函數(shù)為高階函數(shù),show 和 nick 都屬于高階函數(shù)泥张。
python 內(nèi)置函數(shù)中,典型的高階函數(shù)是 map渗钉,map 接收一個函數(shù)和一個迭代對象作為參數(shù),調(diào)用 map 時鳄橘,依次把迭代對象的元素作為參數(shù)調(diào)用該函數(shù):

>>> map(foo, ['the', 'zen', 'of', 'python'])
<map object at 0x020D0250>
>>> 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 函數(shù)的效率更高一點

五、函數(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

這個函數(shù)的目的是取出字符串的第一個字符后再計算它的長度本刽。get_length 調(diào)用時鲸湃,先執(zhí)行 1 處的代碼,發(fā)現(xiàn)有調(diào)用 clean 函數(shù)笋除,接著執(zhí)行 2 的代碼,把返回值賦值給 new_text垃它,再執(zhí)行后續(xù)代碼。

>>> clean("python")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'clean' is not defined

函數(shù)中里面的嵌套函數(shù)不能在函數(shù)外面被調(diào)用嗤瞎,只有局部使用域。

六贝奇、實現(xiàn)了 call的類也可以作為函數(shù)

對于一個自定義的類靠胜,如果實現(xiàn)了 call 方法,那么該類的實例對象的行為就是一個函數(shù)浪漠,可以被調(diào)用:

>>> class ADD:
...     def __init__(self, n):
...         self.n = n
...     def __call__(self, x):
...         return self.n + x
...     
>>> add = ADD(1)
>>> add(4)
5
>>> ADD(1)(4)
5

執(zhí)行 add(4) 相當(dāng)于調(diào)用 ADD.call(add, 4),self 就是實例對象 add该镣,self
.n 等于 1响谓,所以返回值是:1 + 4:

add(4)
  ||
Add(1)(4)
  ||
Add.__call__(add, 4)

確定對象是否可以調(diào)用,可以用內(nèi)置函數(shù) callable 來判斷娘纷。

>>> callable(foo)
True
>>> callable(1)
False
>>> callable(int)
True

總結(jié)

python 中包含函數(shù)在內(nèi)的一切皆為對象,函數(shù)作為第一類對象赖晶,支持賦值給變量,支持作為參數(shù)傳遞給其他函數(shù)捂贿,支持作為其他函數(shù)的返回值胳嘲,支持函數(shù)的嵌套,實現(xiàn)了 call 方法的類實例對象也可以當(dāng)做函數(shù)被調(diào)用胎围。






有點不明白,調(diào)用函數(shù)和類汽纤,什么時候需要寫 ()福荸,什么時候不需要寫:

函數(shù):

>>> def foo(text):
...     return len(text)
...
>>> def nick():
...     return foo

a = nick 調(diào)用的 是 nick 函數(shù)本身,有沒有參數(shù)都可以這樣寫背传,相當(dāng)于給函數(shù)起個別名台夺;
b = nick() 調(diào)用的是 nick 函數(shù)的返回值(foo),nick(var) 函數(shù)必須寫完整颤介,不然無法返回值;
nick()(var)nick()foo 函數(shù)冤灾,nick()(var) 是函數(shù) foo 的返回值,等同于 b(var)韵吨;

類:

>>> class test(object):
...     y = "me"
...     def __init__(self):
...         self.y = 'you'
...         
>>> a = test
>>> a
<class 'test'>
>>> print(a.y)
me
>>> a.y
'me'
>>> b = test()
>>> b
<test object at 0x020D0E50>
>>> b.y
'you'
>>> print(b.y)
you

不帶括號移宅,調(diào)用的是類本身,沒有執(zhí)行 __init__ 函數(shù)盏浇;帶括號的實例化方法調(diào)用了 __init__() 函數(shù),此時必須傳入需要的參數(shù)绢掰;

函數(shù)帶不帶括號童擎,決定了是調(diào)用當(dāng)前函數(shù),還是調(diào)用返回值
類帶不帶括號班挖,決定了掉不掉用 __init__ 方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芯砸,一起剝皮案震驚了整個濱河市给梅,隨后出現(xiàn)的幾起案子动羽,更是在濱河造成了極大的恐慌,老刑警劉巖运吓,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拘哨,死亡現(xiàn)場離奇詭異,居然都是意外死亡倦青,警方通過查閱死者的電腦和手機(jī)站欺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磷账,“玉大人贾虽,你說我怎么就攤上這事∨罨恚” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵取募,是天一觀的道長蟆技。 經(jīng)常有香客問我,道長旺聚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任砰粹,我火速辦了婚禮造挽,結(jié)果婚禮上弄痹,老公的妹妹穿的比我還像新娘界酒。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布岳掐。 她就那樣靜靜地躺著,像睡著了一般串述。 火紅的嫁衣襯著肌膚如雪寞肖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天觅赊,我揣著相機(jī)與錄音,去河邊找鬼吮螺。 笑死帕翻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嘀掸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼泉蝌,長吁一口氣:“原來是場噩夢啊……” “哼衫仑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粥鞋,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瞄崇,失蹤者是張志新(化名)和其女友劉穎壕曼,沒想到半個月后等浊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轧飞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年过咬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掸绞。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡衔掸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敞映,到底是詐尸還是另有隱情,我是刑警寧澤驱显,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布瞳抓,位于F島的核電站,受9級特大地震影響栓霜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胳蛮,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一丛晌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧澎蛛,春花似錦、人聲如沸呆馁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至畔咧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盒卸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留煮寡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓幸撕,卻偏偏與公主長得像外臂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宋光,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355