python函數(shù)

函數(shù)名其實就是指向一個函數(shù)對象的引用,完全可以把函數(shù)名賦給一個變量,相當于給這個函數(shù)起了一個“別名”:
a = ab//把函數(shù)賦給一個變量a print(a(-1))

1、定義函數(shù)

在Python中,定義一個函數(shù)要使用def語句,依次寫出函數(shù)名、括號、括號中的參數(shù)和冒號:,然后,在縮進塊中編寫函數(shù)體,函數(shù)的返回值用return語句返回。
# 定義一個函數(shù)my_abs()求絕對值
def my_abs(x): if x > 0: return x else : return -x x = -10 print(my_abs(x))
空函數(shù)
如果想定義一個什么事也不做的空函數(shù),可以用pass語句:
def nop(): pass

2、函數(shù)的分類
  • 必選參數(shù)
  • 默認參數(shù)
    # 定義含有默認參數(shù)的函數(shù)
    def enroll (name, gender, age=18, city='Beijing'): print('name:', name, 'gender:', gender, 'age:', age, 'city:', city) enroll('chenli', '男')
    結(jié)果:
    name: chenli gender: 男 age: 18 city: Beijing

有多個默認參數(shù)時,調(diào)用的時候,既可以按順序提供默認參數(shù),比如調(diào)用enroll('Bob', 'M', 7),意思是,除了name,gender這兩個參數(shù)外,最后1個參數(shù)應(yīng)用在參數(shù)age上,city參數(shù)由于沒有提供,仍然使用默認值。

也可以不按順序提供部分默認參數(shù)。當不按順序提供部分默認參數(shù)時,需要把參數(shù)名寫上。比如調(diào)用enroll('Adam', 'M', city='Tianjin'),意思是,city參數(shù)用傳進去的值,其他默認參數(shù)繼續(xù)使用默認值。

Python 默認參數(shù)提高了變成效率,但是這里面的坑也是坑死人不償命,使用稍微不正確,會造成致命的失誤
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def test(lang=[]): lang.append('python') return lang
當老實調(diào)用時,結(jié)果如你所愿
print(test(['js','go'])) print(test(['c','java']))
結(jié)果如下
['js', 'go', 'python'] ['c', 'java', 'python'] [Finished in 0.1s]
但是如果多次使用默認參數(shù)調(diào)用時,奇跡出現(xiàn)了
print(test()) print(test())
結(jié)果如下:
['python'] ['python', 'python'] [Finished in 0.1s]
或許有人對此感到很困惑,為什么默認參數(shù)會記住更新過的默認參數(shù)

分析:
函數(shù)在定義的時候,默認參數(shù)lang的值就已經(jīng)聲明了,即空的 [],也就是說 默認參數(shù) 指向?qū)ο?[],在多次調(diào)用默認參數(shù)的情況下,就改變了默認參數(shù)指向?qū)ο蟮臄?shù)據(jù),默認參數(shù) 指向?qū)ο蟮臄?shù)據(jù)變了,下次再調(diào)用時,默認參數(shù)已經(jīng)變了,即不再是你希望的空的[]

為了便于理解等同下面這段:
temp = [] def test(lang=temp): lang.append('python') return lang
這樣就好看多了,多次調(diào)用時,temp 也在不斷的變化

注意函數(shù)默認參數(shù)和函數(shù)中的參數(shù)的上下文環(huán)境
結(jié)論

定義函數(shù)默認參數(shù)時,函數(shù)默認參數(shù)必須指向不變對象,建議使用 None,str 這些不可變對象處理

重新修改代碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
`
def test(lang=None):

if lang is None:
lang = []
lang.append('python')
return lang
調(diào)用
print(test())
print(test())
結(jié)果:
['python']
['python']
[Finished in 0.2s]
`

  • 可變參數(shù)
    定義可變參數(shù)和定義一個list或tuple參數(shù)相比,僅僅在參數(shù)前面加了一個*號。可變參數(shù)允許你傳入0個或任意個參數(shù),這些可變參數(shù)在函數(shù)調(diào)用時自動組裝為一個tuple。在函數(shù)內(nèi)部,參數(shù)numbers接收到的是一個tuple,因此,函數(shù)代碼完全不變。但是,調(diào)用該函數(shù)時,可以傳入任意個參數(shù),包括0個參數(shù):
    #定義一個可選參數(shù)的函數(shù)
    def calc (*numbers):
    sum = 0
    for n in numbers:
    sum += n
    return sum
    print(calc())
    print(calc(1,23,4))
    結(jié)果:
    0 28 [Finished in 0.2s]
    如果已經(jīng)有一個list或者tuple,要調(diào)用一個可變參數(shù)怎么辦?可以這樣做:
    num = (1, 2, 3) print(calc(*num))
    結(jié)果:
    6 [Finished in 0.1s]

  • 關(guān)鍵字參數(shù)
    而關(guān)鍵字參數(shù)允許你傳入0個或任意個含參數(shù)名的參數(shù),這些關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動組裝為一個dict。請看示例:
    #定義關(guān)鍵字參數(shù)的函數(shù)
    def person(name, age, **kw): print('name:', name, 'age:', age, 'other', kw) P1=person('chenli', '19') P2=person('haha', '20', city='Beijing') print(P1, P2)
    結(jié)果:
    name: chenli age: 19 other {} name: haha age: 20 other {'city': 'Beijing'} None None [Finished in 0.2s]
    關(guān)鍵字參數(shù)有什么用?它可以擴展函數(shù)的功能。

  • 命名關(guān)鍵字參數(shù)
    如果要限制關(guān)鍵字參數(shù)的名字,就可以用命名關(guān)鍵字參數(shù),例如,只接收city和job作為關(guān)鍵字參數(shù)。這種方式定義的函數(shù)如下:
    #定義含命名關(guān)鍵字參數(shù)的函數(shù),命名關(guān)鍵字的作用是限定關(guān)鍵字參數(shù)的名字
    def person(name, age, *, city, job): print(name, age, city, job) person('chenli', 10, city = 'Beijing', job='Engineer')``#調(diào)用方式
    結(jié)果:
    chenli 10 Beijing Engineer [Finished in 0.2s]
    和關(guān)鍵字參數(shù) **kw不同,命名關(guān)鍵字參數(shù)需要一個特殊分隔符 *,*后面的參數(shù)被視為命名關(guān)鍵字參數(shù)。
    如果函數(shù)定義中已經(jīng)有了一個可變參數(shù),后面跟著的命名關(guān)鍵字參數(shù)就不再需要一個特殊分隔符*了:
    使用命名關(guān)鍵字參數(shù)時,要特別注意,如果沒有可變參數(shù),就必須加一個*作為特殊分隔符。如果缺少*,Python解釋器將無法識別位置參數(shù)和命名關(guān)鍵字參數(shù):

  • 參數(shù)組合
    在Python中定義函數(shù),可以用必選參數(shù)、默認參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù),這5種參數(shù)都可以組合使用。但是請注意,參數(shù)定義的順序必須是:必選參數(shù)、默認參數(shù)、可變參數(shù)、命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)
    def f1(a, b, c=0, *args, **kw): print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) def f2(a, b, c=0, *, d, **kw): print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw) f1(1, 2) f1(1, 2, c=3) f1(1, 2, 3, 'a', 'b') f1(1, 2, 3, 'a', 'b', x=99) f2(1, 2, d =99, ext =None) args = (1, 2, 3) args1 = (1, 2, 3, 4) kw = {'d': 99, 'x': '#'} f1(*args1, **kw)``#最神奇的是通過一個tuple和dict,你也可以調(diào)用上述函數(shù):
    f2(*args, **kw)``#最神奇的是通過一個tuple和dict,你也可以調(diào)用上述函數(shù):
    對于任意函數(shù),都可以通過類似func(*args, **kw)的形式調(diào)用它,無論它的參數(shù)是如何定義的。

3.遞歸函數(shù)

在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個函數(shù)在內(nèi)部調(diào)用自身本身,這個函數(shù)就是遞歸函數(shù)。
遞歸函數(shù)的優(yōu)點是定義簡單,邏輯清晰。理論上,所有的遞歸函數(shù)都可以寫成循環(huán)的方式,但循環(huán)的邏輯不如遞歸清晰。
使用遞歸函數(shù)需要注意防止棧溢出。在計算機中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的,每當進入一個函數(shù)調(diào)用,棧就會加一層棧幀,每當函數(shù)返回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會導(dǎo)致棧溢出。可以試試fact(1000):
def fact(n): if n == 1: return 1 return n*fact(n-1) print(fact(1000))
結(jié)果:
RecursionError: maximum recursion depth exceeded in comparison
解決遞歸調(diào)用棧溢出的方法是通過尾遞歸優(yōu)化,事實上尾遞歸和循環(huán)的效果是一樣的,所以,把循環(huán)看成是一種特殊的尾遞歸函數(shù)也是可以的。

尾遞歸是指,在函數(shù)返回的時候,調(diào)用自身本身,并且,return語句不能包含表達式。這樣,編譯器或者解釋器就可以把尾遞歸做優(yōu)化,使遞歸本身無論調(diào)用多少次,都只占用一個棧幀,不會出現(xiàn)棧溢出的情況。
def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num-1, num * product) print(fact(100)) print(fact_iter(100,1))
可以看到,return fact_iter(num - 1, num * product)僅返回遞歸函數(shù)本身,num - 1和num * product在函數(shù)調(diào)用前就會被計算,不影響函數(shù)調(diào)用。

尾遞歸調(diào)用時,如果做了優(yōu)化,棧不會增長,因此,無論多少次調(diào)用也不會導(dǎo)致棧溢出。

遺憾的是,大多數(shù)編程語言沒有針對尾遞歸做優(yōu)化,Python解釋器也沒有做優(yōu)化,所以,即使把上面的fact(n)函數(shù)改成尾遞歸方式,也會導(dǎo)致棧溢出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內(nèi)容

  • 調(diào)用函數(shù) 函數(shù)名,參數(shù),參數(shù)類型和個數(shù)要和定義時一樣,如 數(shù)據(jù)類型轉(zhuǎn)換 函數(shù)名其實是一個函數(shù)對象的引用,可以把函數(shù)...
    齊天大圣李圣杰閱讀 407評論 0 1
  • Python 是一種相當高級的語言,通過 Python 解釋器把符合語法的程序代碼轉(zhuǎn)換成 CPU 能夠執(zhí)行的機器碼...
    Python程序媛閱讀 1,930評論 0 3
  • 1.參數(shù)的介紹 (1)可變和不可變參數(shù) (2)必選參數(shù) (3)默認參數(shù) (4)可變參數(shù) (5)關(guān)鍵字參數(shù) 1.1....
    華麗的微笑閱讀 409評論 0 1
  • 要調(diào)用一個函數(shù),需要知道函數(shù)的名稱和參數(shù),比如求絕對值的函數(shù)abs,只有一個參數(shù)。可以直接從Python的官方網(wǎng)站...
    zzj丶閱讀 349評論 0 0
  • 洛陽是中國名列第二的古城,只屈居于聲名煊赫的十三朝古都、偉大的西漢和唐的首都,西安之后。按常理洛陽應(yīng)該是極度驕傲的...
    白馬非馬_閱讀 1,764評論 29 20