第五章 函數(shù)的設(shè)計(jì)和使用

將可能需要反復(fù)執(zhí)行的代碼封裝為函數(shù)盏阶,并在需要該段代碼功能的地方調(diào)用亮蒋,不僅可以實(shí)現(xiàn)代碼的復(fù)用煮寡,更重要的是可以保證代碼的一致性,只需要修改該函數(shù)代碼則所有調(diào)用均受到影響趾诗。

5.1 函數(shù)定義與調(diào)用

語法:
def 函數(shù)名([形式參數(shù)表]):
注釋
函數(shù)體
** 注意事項(xiàng)**:

  • 函數(shù)形參不需要聲明類型斜姥,也不需要指定函數(shù)返回值類型。
  • 即使該函數(shù)不需要接收任何參數(shù)沧竟,也必須保留一對(duì)空的圓括號(hào)铸敏。
  • 括號(hào)后面的冒號(hào)必不可少
  • 函數(shù)體相對(duì)于def關(guān)鍵字必須保持一定的空格縮進(jìn)
  • Python允許嵌套定義函數(shù)


    image.png

5.2 形參與實(shí)參

  • 函數(shù)定義時(shí)括弧內(nèi)為形參,一個(gè)函數(shù)可以沒有形參悟泵,但是括弧必須要有杈笔,表示該函數(shù)不接收參數(shù)。
  • 函數(shù)調(diào)用時(shí)向其傳遞實(shí)參糕非,將實(shí)參的值或引用傳遞給形參蒙具。
  • 一般來說,在函數(shù)內(nèi)直接修改形參的值不影響實(shí)參朽肥。
  • 但是禁筏,列表、字典衡招、集合等可變序列作為函數(shù)參數(shù)時(shí)篱昔,在函數(shù)內(nèi)部使用下標(biāo)或序列自身直刺的方式為可變序列增加、刪除元素或修改元素值時(shí),修改后的結(jié)果是可以反映到函數(shù)之外的州刽,即實(shí)參也得到了相應(yīng)的修改空执。
  • 對(duì)于絕大多數(shù)情況下,在函數(shù)內(nèi)部直接修改形參的值不會(huì)影響實(shí)參穗椅。例如下面的示例:
>>> def addone(a):
    print(a)
    a+=1
    print(a)

    
>>> a=3
>>> addone(a)
3
4
>>> a
3
>>> def modify(v):
    v[0]=v[0]+1

    
>>> a=[1,2,3]
>>> modify(a)
>>> a
[2, 2, 3]

5.3 參數(shù)類型

  • 在Python中辨绊,函數(shù)參數(shù)有很多種:可以為位置參數(shù)、默認(rèn)值參數(shù)匹表、關(guān)鍵參數(shù)门坷、可變長度參數(shù)等。
  • Python函數(shù)的定義非常靈活袍镀,在定義函數(shù)時(shí)不需要指定參數(shù)的類型拜鹤,也不需要指定函數(shù)的類型,完全由調(diào)用者決定流椒。
  • 函數(shù)編寫如果有問題敏簿,只有在調(diào)用時(shí)才能被發(fā)現(xiàn),傳遞某些參數(shù)時(shí)執(zhí)行正確宣虾,而傳遞另一些類型的參數(shù)時(shí)則出現(xiàn)錯(cuò)誤惯裕。

5.3.1 位置參數(shù)

位置參數(shù)(positional arguments),調(diào)用函數(shù)時(shí)實(shí)參和形參的順序必須嚴(yán)格一致绣硝,數(shù)量必須相同蜻势。

>>> def demo(a,b,c):
    print(a,b,c)

    
>>> demo(3,4,5)    #按位置傳遞參數(shù)
3 4 5
>>> demo(3,5,4)
3 5 4
>>> demo(1,2,3,4)   #實(shí)參與形參數(shù)量必須相同
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    demo(1,2,3,4)   #實(shí)參與形參數(shù)量必須相同
TypeError: demo() takes 3 positional arguments but 4 were given

5.3.2 默認(rèn)值參數(shù)

語法:
def 函數(shù)名(......,形參名=默認(rèn)值)
函數(shù)體

  • 在調(diào)用帶有默認(rèn)值參數(shù)的函數(shù)時(shí),可以不用為設(shè)置了默認(rèn)值的形參進(jìn)行傳值鹉胖,此時(shí)函數(shù)將會(huì)直接使用函數(shù)定義時(shí)設(shè)置的默認(rèn)值握玛,當(dāng)然也可以通過顯式賦值來替換其默認(rèn)值。在調(diào)用函數(shù)時(shí)是否為默認(rèn)值參數(shù)傳遞實(shí)參是可選的甫菠。
  • 需要注意的是挠铲,在定義帶有默認(rèn)值參數(shù)的函數(shù)時(shí),任何一個(gè)默認(rèn)值參數(shù)右邊都不能再出現(xiàn)沒有默認(rèn)值的普通位置參數(shù)寂诱,否則會(huì)提示語法錯(cuò)誤拂苹。
>>> def f(a=3,b,c=5):
    print(a,b,c)
    
SyntaxError: non-default argument follows default argument
>>> def f(a,b,c=5):
    print(a,b,c)

    
>>> #調(diào)用帶有默認(rèn)值參數(shù)的函數(shù)時(shí),可以不對(duì)默認(rèn)值參數(shù)進(jìn)行賦值痰洒,也可以賦值瓢棒,具有較大的靈活性
>>> def say(message,times=1):
    print(message*times)

    
>>> say('hello')
hello
>>> say('hello',3)
hellohellohello
  • 函數(shù)的默認(rèn)值參數(shù)是在函數(shù)定義時(shí)確定值的,所以只會(huì)被初始化一次丘喻。
>>> i=3
>>> def f(n=i):
    print(n)  #參數(shù)n的值僅取決于i的當(dāng)前值

    
>>> f()
3
>>> i=5   #函數(shù)定義后修改i的值不影響參數(shù)n的默認(rèn)值
>>> f()
3
>>> i=7
>>> f()
3
>>> def f(n=i):    #重新定義函數(shù)
    print(n)

    
>>> f()
7
  • 注:可以使用函數(shù)名.func_defaults查看默認(rèn)參數(shù)的當(dāng)前值脯宿。

5.3.3 關(guān)鍵參數(shù)

  • 關(guān)鍵參數(shù)主要指實(shí)參,即調(diào)用函數(shù)時(shí)的參數(shù)傳遞方式泉粉。
  • 通過關(guān)鍵參數(shù)傳遞连霉,實(shí)參順序和形參順序可以不一致,但不影響傳遞結(jié)果,避免了用戶需要牢記位置參數(shù)順序的麻煩窘面。
>>> def demo(a,b,c=5):
    print(a,b,c)

    
>>> demo(3,7)
3 7 5
>>> demo(c=8,a=9,b=0)
9 0 8

5.3.4 可變長度參數(shù)

  • 可變長度參數(shù)主要有兩種形式:parameter和*parameter翠语,前者用來接受多個(gè)實(shí)參并將其放在一個(gè)元組中叽躯,后者接收字典形式的實(shí)參财边。
>>> def demo(*p):
    print(p)

    
>>> demo(1,2,3)
(1, 2, 3)
>>> #第二種形式:
>>> def demo(**p):
    for item in p.items():
        print(item)

        
>>> demo(x=1,y=2,z=3)
('x', 1)
('y', 2)
('z', 3)
  • 幾種不同類型的參數(shù)可以混合使用,但是不建議這樣做
>>> def func_4(a,b,c=4,*aa,**bb):
    print(a,b,c)
    print(aa)
    print(bb)

    
>>> func_4(1,2,3,4,5,6,7,8,9,xx='1',yy='2',zz=3)
1 2 3
(4, 5, 6, 7, 8, 9)
{'xx': '1', 'yy': '2', 'zz': 3}

5.3.5 參數(shù)傳遞的序列解包

  • 傳遞參數(shù)時(shí)点骑,可以通過在實(shí)參序列前加星號(hào)將其解包酣难,然后傳遞給多個(gè)單變量形參。
>>> def demo(a,b,c):
    print(a+b+c)

    
>>> seq=[1,2,3]
>>> demo(*seq)
6
>>> tup=(1,2,3)
>>> demo(*tup)
6

5.4 變量類型與其作用域

  • 變量起作用的代碼范圍稱為變量的作用域黑滴,不同作用域內(nèi)變量名可以相同憨募,互不影響。
  • 在函數(shù)內(nèi)部定義的普通變量只在函數(shù)內(nèi)部起作用袁辈,稱為局部變量菜谣。當(dāng)函數(shù)執(zhí)行結(jié)束后,局部變量自動(dòng)刪除晚缩,不再可以使用尾膊。
  • 局部變量的引用比全局變量速度快,應(yīng)優(yōu)先考慮使用荞彼。

5.4.1 局部變量

  • 注意:在某個(gè)作用域內(nèi)任意位置只要有為變量賦值的操作冈敛,該變量在這個(gè)作用域內(nèi)就是局部變量,除非使用global進(jìn)行了聲明鸣皂。
>>> x=3
>>> def f():
    print(x)  #此語句會(huì)引發(fā)異常抓谴,因?yàn)樽兞縳現(xiàn)在還不存在
    x=5  #有賦值操作,因此在整個(gè)作用域內(nèi)x都是局部變量
    print(x)

    
>>> f()
Traceback (most recent call last):
  File "<pyshell#86>", line 1, in <module>
    f()
  File "<pyshell#85>", line 2, in f
    print(x)  #此語句會(huì)引發(fā)異常寞缝,因?yàn)樽兞縳現(xiàn)在還不存在
UnboundLocalError: local variable 'x' referenced before assignment
  • 注意:如果局部變量與全局變量具有相同的名字癌压,那么該局部變量會(huì)在自己的作用域內(nèi)暫時(shí)隱藏同名的全局變量。
>>> def demo():
    x=3
    print(x)

    
>>> x=5
>>> x
5
>>> demo()
3
>>> x
5

5.4.2 全局變量

  • 如果在函數(shù)內(nèi)部修改一個(gè)定義在函數(shù)外的變量值荆陆,必須使用global明確聲明措拇,否則會(huì)自動(dòng)創(chuàng)建新的局部變量。
  • 一個(gè)變量已在函數(shù)外定義慎宾,如果在函數(shù)內(nèi)需要為這個(gè)變量賦值丐吓,并要將這個(gè)賦值結(jié)果反映到函數(shù)外,可以在函數(shù)內(nèi)使用global將其聲明為全局變量趟据。
  • 如果一個(gè)變量在函數(shù)外沒有定義券犁,在函數(shù)內(nèi)部使用global,直接將一個(gè)變量定義為全局變量汹碱,該函數(shù)執(zhí)行后粘衬,將增加一個(gè)新的全局變量。

5.4.3 案例

>>> def demo():
    x=3
    print(x)

    
>>> x=5
>>> x
5
>>> demo()
3
>>> x
5
>>> def demo():
    global x #聲明或創(chuàng)建全局變量
    x=3    #修改全局變量的值
    y=4    #局部變量
    print(x,y)

    
>>> x=5  #在函數(shù)外定義了全局變量x
>>> demo()   #調(diào)用修改了全局變量x的值
3 4
>>> x
3
>>> y    #局部變量在函數(shù)運(yùn)行完自動(dòng)刪除
Traceback (most recent call last):
  File "<pyshell#104>", line 1, in <module>
    y    #局部變量在函數(shù)運(yùn)行完自動(dòng)刪除
NameError: name 'y' is not defined
>>> del x  #刪除全局變量
>>> x
Traceback (most recent call last):
  File "<pyshell#106>", line 1, in <module>
    x
NameError: name 'x' is not defined
>>> demo()  #本次調(diào)用創(chuàng)建了全局變量
3 4
>>> x
3
>>> y
Traceback (most recent call last):
  File "<pyshell#109>", line 1, in <module>
    y
NameError: name 'y' is not defined

5.5 lambda表達(dá)式

  • lambda表達(dá)式可以用來聲明匿名函數(shù),即沒有函數(shù)名字的臨時(shí)使用的小函數(shù)稚新,只可以包含一個(gè)表達(dá)式勘伺,且該表達(dá)式的計(jì)算結(jié)果為函數(shù)的返回值,不允許包含其他復(fù)雜的語句褂删,但在表達(dá)式中可以調(diào)用其他函數(shù)飞醉。
>>> f=lambda x,y,z:x+y+z   #可以為lambda表達(dá)式起名字
>>> f(1,2,3)    #像函數(shù)一樣調(diào)用
6
>>> g=lambda x,y=2,z=3:x+y+z    #參數(shù)默認(rèn)值
>>> g(1)
6
>>> print(g(2,z=4,y=5))    #關(guān)鍵參數(shù)
11
>>> L=[(lambda x:x**2),(lambda x:x**3),(lambda x:x**4)]
>>> print(L[0](2),L[1](2),L[2](2))
4 8 16
>>> D={'f1':(lambda:2+3),'f2':(lambda:2*3),'f3':(lambda:2**3)}
>>> print(D['f1'](),D['f2'](),D['f3']())
5 6 8

5.6 高級(jí)話題

  • 內(nèi)置函數(shù)map可以將一個(gè)函數(shù)作用到一個(gè)序列或迭代器對(duì)象上。
>>> list(map(str,range(5)))
['0', '1', '2', '3', '4']
>>> def add5(v):
    return v+5

>>> list(map(add5,range(10)))
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
  • 內(nèi)置函數(shù)filter將一個(gè)函數(shù)作用到一個(gè)序列上屯阀,返回該序列中使得該函數(shù)返回值為True的那些元素組成的列表缅帘、元組或字符串。
>>> seq=['foo','x41','?!','***']
>>> def func(x):
    return x.isalnum()

>>> filter(func,seq)
<filter object at 0x0000015010813748>
>>> list(filter(func,seq))
['foo', 'x41']
  • 作業(yè)
  1. 一個(gè)數(shù)如果恰好等于它的因子之和难衰,這個(gè)數(shù)就稱為"完數(shù)"钦无。例如,6的因子為1盖袭、2失暂、3,而6=1+2+3鳄虱,因此6是完數(shù)弟塞。編程,找出1000之內(nèi)的所有完數(shù)醇蝴,并輸出該完數(shù)及對(duì)應(yīng)的因子宣肚。
  2. 判斷101—200之間有多少個(gè)素?cái)?shù),并輸出所有素?cái)?shù)悠栓。(注:判斷素?cái)?shù)的方法:用一個(gè)數(shù)分別去除2到sqrt(這個(gè)數(shù))霉涨,如果能被整除,則表明此數(shù)不是素?cái)?shù)惭适,反之是素?cái)?shù)笙瑟。)
  3. 請輸出1000以內(nèi)的斐波那契數(shù)列。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末癞志,一起剝皮案震驚了整個(gè)濱河市往枷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凄杯,老刑警劉巖错洁,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異戒突,居然都是意外死亡屯碴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門膊存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來导而,“玉大人忱叭,你說我怎么就攤上這事〗褚眨” “怎么了韵丑?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長虚缎。 經(jīng)常有香客問我撵彻,道長,這世上最難降的妖魔是什么遥巴? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任千康,我火速辦了婚禮享幽,結(jié)果婚禮上铲掐,老公的妹妹穿的比我還像新娘。我一直安慰自己值桩,他們只是感情好摆霉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奔坟,像睡著了一般携栋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咳秉,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天婉支,我揣著相機(jī)與錄音,去河邊找鬼澜建。 笑死向挖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炕舵。 我是一名探鬼主播何之,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼咽筋!你這毒婦竟也來了溶推?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤奸攻,失蹤者是張志新(化名)和其女友劉穎蒜危,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睹耐,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辐赞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疏橄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片占拍。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡略就,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晃酒,到底是詐尸還是另有隱情表牢,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布贝次,位于F島的核電站崔兴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蛔翅。R本人自食惡果不足惜敲茄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望山析。 院中可真熱鬧堰燎,春花似錦、人聲如沸笋轨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爵政。三九已至仅讽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钾挟,已是汗流浹背洁灵。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掺出,地道東北人徽千。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像蛛砰,于是被迫代替她去往敵國和親罐栈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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