文章目錄
1.什麼是函數
- 函數
(function)
由若干條語句組成,用於實現特定的功能 - 函數的本質就是對功能的封裝
- 一旦定義了函數,就可以在程序中需要實現該功能的位置調用函數
- 函數名不能重複(沒有重載)
2.定義和調用函數
- 使用
de
f關鍵字來創建python自定義函數 - 可以直接使用函數名來調用函數
語法結構:
def 函數名 (參數列表)
函數體
return 數據
- 參數列表可以爲空,也可以包含多個參數
return
可寫可不寫,不寫默認返回None
<1> 定義一個空函數
def test():
pass
<2> 無參函數
def test():
print('in test')
test()
運行結果
in test
儘管定義了函數,只要不調用函數,那這個函數是不會執行的
def hh():
print('hello')
#沒有調用這個函數,該函數不執行
<3> 有參函數 (參數—argument/arg)
def test1(arg):
print('in test')
test1(1)
def test2(arg):
print('in test',arg)
#參數類型沒有要求,可以是任意類型
test2(1)
test2('hello')
test2([100,200])
def test3(arg,arg1,arg2):
print('in test',arg,arg1,arg2)
# 1-->arg python-->arg1 [1,2]-->arg2
test3(1,'python',[1,2])
運行結果
in test
in test 1
in test hello
in test [100, 200]
in test 1 python [1, 2]
- 參數類型沒有要求,可以是任意類型
- 參數的個數沒有要求
3. 返回值
def test(arg,arg1,arg2):
print('in test',arg,arg1,arg2)
return 1 #返回1
ret=test(1,2,3) #調用test(1,2,3)函數,然後把返回值給ret變量
print(ret)
運行結果
in test 1 2 3
1
可以返回任何類型
def test1(arg,arg1,arg2):
print('in test1',arg,arg1,arg2)
return [4,5]
ret=test1(1,2,3)
print(ret)
def test2(arg,arg1,arg2):
print('in test2',arg,arg1,arg2)
return [arg,arg1,arg2]
ret=test2(1,2,3)
print(ret)
運行結果
in test1 1 2 3
[4, 5]
in test2 1 2 3
[1, 2, 3]
如果沒有return那麼就返回None return|return None |不寫
def test3(arg,arg1,arg2):
print('in test3',arg,arg1,arg2)
ret=test3(1,2,3)
print(ret)
def test4(arg,arg1,arg2):
print('in test4',arg,arg1,arg2)
return
ret=test4(1,2,3)
print(ret)
def test5(arg,arg1,arg2):
print('in test5',arg,arg1,arg2)
return None
ret=test5(1,2,3)
print(ret)
運行結果
in test3 1 2 3
None
in test4 1 2 3
None
in test5 1 2 3
None
def test1():
print('in the test1')
def test():
print('in the test')
return test1 #返回test1()的內存地址
res=test()
print(res()) #test1()
#因爲test1沒有return 所以默認返回None
運行結果
in the test
in the test1
None
練習題:
#我們系統函數test6 如果都是整數 那麼返回數組[1,2,3]
#如果參數全是字符串 就返回 arg arg1 arg2 'welcome to python'
def test6(arg,arg1,arg2):
#判斷參數的類型
#isinstance 是系統的 用來判斷參數是否是你想要的那個類型
if isinstance(arg,int) and isinstance(arg1,int) and isinstance(arg2,int):
return [arg,arg1,arg2]
if isinstance(arg,str) and isinstance(arg1,str) and isinstance(arg2,str):
return arg+' '+arg1+' '+arg2
#如果參數並不都是整數或者並不都是字符串,那就返回'Error'
return 'Error'
c=test6(1,2,3)
print(c)
c=test6('welcome','to','python')
print(c)
c=test6(1,2,'python')
print(c)
運行結果
[1, 2, 3]
welcome to python
Error
4.形參和實參
形參:
- 形參變量只有在被調用時才分配內存單元,在調用結束時,即可釋放預分配的內存單元
- 形參只在函數內部有效
- 函數調用結束返回主調用函數後則不能再使用該形參變量
實參:
- 實參可以是常量、變量、表達式、函數等
- 無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳遞給形參
- 應預先用賦值,輸入等辦法是參數獲得確定值
def calc(x,y): #x,y是形參
res=x**y
return res
c=calc(2,3) #2,3是實參
#有人想這個不就是 x=2,y=3的賦值操作,那就可以直接輸出x,y
#但是不要忘了形參只有在被調用時才分配內存單元
#print(x) 錯誤
#print(y) 錯誤
print(c)
運行結果
8
5.函數參數
def test7(name,age,score):
print(name,age,score)
<1>普通參數
test7('yang',18,80)
運行結果
yang 18 80
普通參數的參數順序不能改變
tset7(18,'yang',80) 是錯的
<2> 關鍵字參數
順序可以隨便設置
test7(name='yang',age=18,score=80)
test7(age=18,score=80,name='yang')
運行結果
yang 18 80
yang 18 80
<3> 普通參數和關鍵字參數混合使用
- 注意
python
要求 普通參數和關鍵字參數如果混合使用那麼你必須先傳普通參數,然後再傳關鍵字參數
test7('yang',18,score=80)
test7('yang',age=18,score=80)
test7(name='yang',age=18,score=80)
#test7('yang',age=18,80) 錯誤
#test7('yang',70,age=18) 錯誤 70傳給age而後面的參數又給age賦值了一個數,那就沒有參數傳給score了
運行結果
yang 18 80
yang 18 80
yang 18 80
<4>默認參數
def test8(name,age,score=60):
print(name,age,score)
#因爲已經有一個參數有了默認值,所以我們傳入兩個參數就可以
test8('yang',18)
#當然也可以傳三個參數,但是已經默認的那個參數如果也要傳的話,它會自動變爲傳入的數值
test8('yang',18,70)
運行結果
yang 18 60
yang 18 70
默認參數後面不能有普通參數
def test9(name,age=18,score=80):
print(name,age,score)
test9('yang')
# def test9(name,age=18,score): 錯誤
運行結果
yang 18 80
<5> 可變長參數
(1) *args
*args
表示一個可變元組args
就是一個元組 元組就是隻讀的數組/列表- 參數名就是
args
*
表示args
裏面的參數可變
def test10(*args):
print(args)
test10(1,2,3) #可以隨便添加參數
運行結果
(1, 2, 3)
def test11(*args):
print(args,type(args)) #只輸出args的值和類型
value=0
for i in args: #因爲args是一個元組,所以需要遍歷才能獲取每個元素
value+=i
return value
c=test11(1,2,3,4)
print(c)
c=test11() #沒有給args傳值
print(c)
運行結果
(1, 2, 3, 4) <class 'tuple'>
10
() <class 'tuple'>
0
這個可變參數 前面兩個參數v1,v2是默認參數,後面的參數是可變的
def test12(v1,v2,*args):
print(args,type(args)) #只輸出args的值和類型
value=0
for i in args:
value+=i
return value
c=test12(1,2) #v1=1,v2=2,沒有給args傳值
print(c)
運行結果
() <class 'tuple'>
0
def test13(v1,v2,*args):
print(args,type(args)) #只輸出args的值和類型
value=0
for i in args:
value+=i
return value
c=test13(1,2,3) #v1=1,v2=2,args=3
print(c)
運行結果
(3,) <class 'tuple'>
3
def test14(v1,v2,*args):
print(args,type(args)) #輸出args和args的類型
value=(v1+v2) #value不像前兩個賦值爲0,現在的value已經把v1,v2提前加起來了
for i in args:
value+=i
return value
c=test14(1,2,3) #v1=1,v2=2,args=3
print(c)
運行結果
(3,) <class 'tuple'>
6
可變參數傳數組/列表
*list1
就是args
def test14(v1,v2,*args):
print(args,type(args)) #輸出args和args的類型
value=(v1+v2) #value不像前兩個賦值爲0,現在的value已經把v1,v2提前加起來了
for i in args:
value+=i
return value
list1=[1,2,3,4]
c=test14(1,2,1,100,*list1) #v1=1 v2=2 1,100,*list1就是args
#上面的相當於拆成 c=test14(1,2,1,100,1,2,3,4)
print(c)
(1, 100, 1, 2, 3, 4) <class 'tuple'>
114
(2) **kwargs
- 可變參數處理關鍵字參數
kwargs
表示 關鍵字可變參數*
表示普通可變參數(positional
位置參數)**
表示關鍵字可變參數kwargs
是一個字典
def test15(**kwargs):
print(kwargs,type(kwargs))
value=0
for key in kwargs:
v=kwargs[key] #獲取字典裏的值
if isinstance(v,int) or isinstance(v,float): #如果v是整數或者是浮點數那就執行下面的加法運算
value+=v
return value
test15(name='yang')
c=test15(name=10,b=1,c=2,d=3,e=4,f=100.56)
print(c)
運行結果
{'name': 'yang'} <class 'dict'>
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56} <class 'dict'>
120.56
可變參數支持位置參數/普通參數和關鍵字參數
def test16(*args,**kwargs):
print(args)
print(kwargs)
value=0
return value
c=test16(1,2,3,name=10,b=1,c=2,d=3,e=4,f=100.56)
print(c)
運行結果
(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
0
def test17(*args,**kwargs):
print(args)
print(kwargs)
value=0
#先處理位置參數/普通參數
for i in args: #遍歷元組
value+=i
for i in kwargs: #遍歷字典
v=kwargs[i]
value+=v
return value
c=test17(1,2,3,name=10,b=1,c=2,d=3,e=4,f=100.56) #若有字符串的參數還需要判斷並不參與加法運算
print(c)
運行結果
(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
126.56
參數解開
dict2={'name':10,'b':1,'c':2,'d':3,'e':4,'f':100.56}
tuple2=(1,2,3)
# *tuple2 表示把(1,2,3)---->1,2,3
# **dict2 表示把{'name':10,'b':1,'c':2,'d':3,'e':4,'f':100.56}--->name=10,b=1,c=2,d=3,e=4,f=100.56
# **的作用就是把dict2從字典轉換成關鍵字參數
c=test17(*tuple2,**dict2)
print(c)
運行結果
(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
126.56
6.遞歸函數
遞歸函數是指直接或間接調用函數本身的函數
遞歸特性
- 必須有一個明確的結束條件
- 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
- 遞歸效率不高,遞歸層次過多會導致棧溢出
- 在計算機中,函數調用時通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的。所以,遞歸調用的次數過多,會導致棧溢出
使用遞歸函數計算階乘
def fact(n):
if n==1:
return 1
return n*fact(n-1)
print(fact(5)) #5*4*3*2*1
運行結果
120
def calc(n):
print(n)
if int(n/2)==0:
return n
res=calc(int(n/2))
return res
calc(10)
運行結果
10
5
2
1
def calc1(n):
print(n)
if int(n/2)==0:
return n
res=calc1(int(n/2))
return res
res=calc1(10)
print(res)
運行結果
10
5
2
1
1
res的值就是最後得到的1
遞歸函數相當於問路,我問1號朋友怎麼去目的地,1號不知道他去2號,2號不知道他去問3號,3號說我知道怎麼走,這時,我們還要返回正確路線給問路人我,3號告訴2號,2號告訴1號,1號再傳達給我
person_list=['小明','小李','小紅','小藍']
def ask_way(person_list):
print('-'*60) #打印一條分界線
if len(person_list)==0: #到最後一個人還不知道怎麼走
return '沒人知道'
person=person_list.pop(0) #每次都把列表裏的第0個元素刪除並賦值給person
if person=='小紅': #小紅知道正確的路線
return '%s說:我知道路,左走一百米就到了'%person
print('hi 美女[%s],請問你知道華林在哪嗎?'%person) #每當問到一個人就輸出這句話
print('%s回答道:不好意思,我不是很清楚,我幫你問問%s...'%(person,person_list))
res=ask_way(person_list) #把繼續問的人的結果賦值給res,當結果問到時就一層一層的返回給問路的人,並輸出下面的話
print('%s問的結果是:%res'%(person,res))
return res
res=ask_way(person_list)
print(res)
運行結果
------------------------------------------------------------
hi 美女[小明],請問你知道華林在哪嗎?
小明回答道:不好意思,我不是很清楚,我幫你問問['小李', '小紅', '小藍']...
------------------------------------------------------------
hi 美女[小李],請問你知道華林在哪嗎?
小李回答道:不好意思,我不是很清楚,我幫你問問['小紅', '小藍']...
------------------------------------------------------------
小李問的結果是:'小紅說:我知道路,左走一百米就到了'es
小明問的結果是:'小紅說:我知道路,左走一百米就到了'es
小紅說:我知道路,左走一百米就到了