將可能需要反復(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è)
- 一個(gè)數(shù)如果恰好等于它的因子之和难衰,這個(gè)數(shù)就稱為"完數(shù)"钦无。例如,6的因子為1盖袭、2失暂、3,而6=1+2+3鳄虱,因此6是完數(shù)弟塞。編程,找出1000之內(nèi)的所有完數(shù)醇蝴,并輸出該完數(shù)及對(duì)應(yīng)的因子宣肚。
- 判斷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ù)笙瑟。)
- 請輸出1000以內(nèi)的斐波那契數(shù)列。