函數的基本定義
什么是函數?
函數就是具有某個具體功能的工具
為什么要用函數?
提高開發效率
減少代碼冗余
提高程序的擴展性
如何定義一個函數?
def是定義函數的關鍵字
函數名:函數名的命名規則與變量名一致
1.不能以關鍵字命名
2.函數也應該做到見名知意
函數在定義的時候只檢測函數體內的語法,不執行函數體代碼
def func() print('hello')
調用函數的固定格式:
函數名+括號 #func()
函數名只要遇到括號會立即執行函數體代碼
代碼中遇到函數名加括號,優先級最高
先去執行函數,再看下面的代碼
函數的返回值
函數內要想返回給調用者值,必須用關鍵字return
1.不寫return
2.只寫return
3.寫return None
4.寫return返回一個值
5.寫return返回多個值
不寫return:函數默認返回None
def func(): print('hahaha') res = func() print(res)
只寫return:return除了可以返回值之外 還可以直接結束整個函數的運行
只寫return 返回的也是None(None就表示什么都沒有)
def func(): l = ['zhangsan','lisi','wangwu'] while True: for i in l: if i == 'lisi': # 當i為lisi的時候 直接結束函數運行 break return print('asdasdkljlsjadl') # 這一行代碼擁有都不會運行 print(i) res = func() print(res)
寫return None:跟上面的只寫return是一樣的
def func(): return None res = func() print(res)
寫return返回一個值:這個值可以是python任意數據類型
def func(): return '123' def func1(): return [1,2,3] def func2(): return {'name':'zhangsan'} def func3(): return (1,) def func4(): return {1,2,3,4,5} def func5(): return True print(func(),func1(),func2(),func3(),func4(),func5())
寫return返回多個值:return會自動將多個值以元組的形式返回給調用者
def func(): return 1,2,3,4 # 返回的是(1, 2, 3, 4) res = func() print(res) def func1(): return 'a','b','c' # ('a', 'b', 'c') res = func1() print(res) def func2(): return [1,2,3],[1,2,3],[1,2,3] # ([1, 2, 3], [1, 2, 3], [1, 2, 3]) res1 = func2() print(res1) def func3(): return {'name':'zhangsan'},{'username':'lisi'},{'user_name':'wangwu'} # ({'name': 'zhangsan'}, {'username': 'lisi'}, {'user_name': 'wangwu'}) res2 = func3() print(res2)
函數返回的結果全部都是元組類型,因為函數不希望自己處理的結果被修改,那么應該如何返回一個非元組的結果呢?
def func4(): return [[1,2,3,4],[1,2,3,4],[1,2,34]] res = func4() print(res)
# 把所有的結果當成一個結果返回,寫成什么樣的類型就返回什么樣的類型
注意:
1.所有的函數都有返回值,無論你寫不寫return
python中所有的函數都有返回值 不寫的情況下默認返回None
2.光寫return 或者return None並不是為了考慮返回值 而是為了結束函數的運行
函數參數的介紹
函數參數的兩大類型
形參:在函數的定義階段 括號內寫的變量名,叫做該函數的形式參數,簡稱形參
實參:在函數的調用階段,括號內實際傳入的值,叫做實際參數,簡稱實參
形參和實參的關系
形參就相當於變量名,而實參就相當於變量的值
函數調用傳參的過程 就是給形參變量名賦值的過程
注意:形參和實參的綁定關系只在函數的調用階段有效,函數運行結束關系自動解除,只在函數內部有 效,函數外部無任何影響
函數的簡易結構
def 函數名(形參1,形參2,形參3.....):
'''函數的注釋,用來描述該函數的作用依舊各個形參的類型'''
函數體代碼1
函數體代碼2
....
return 函數的返回值
位置參數
定義:在函數定義階段按照位置從左往右依次書寫的變量名 叫做函數位置形參
位置形參在調用的時候 必須為其傳值
求兩個數的大小 返回大的那個(示例)
def my_max(x,y): print(x,y) if x > y: return x else: return y res = my_max(1) #在調用函數的時候 少一個實參不行(位置實參) res = my_max(1,2,3) #在調用函數的時候 多一個實參也不行(位置實參) res = my_max(20,10) #在函數調用的時候 傳入和形參一一對應的參數(位置實參)
res = my_max(y=20,x=10) #在函數調用的時候,使用關鍵字傳參
res = my_max(10,y=20) #位置參數和關鍵字參數混合使用,需要注意的是位置參數必須在前
print(res)
有上面的代碼可以得出:位置實參在函數的調用階段,傳入的參數會按照位置一一對應給形參,而關鍵字參數則是依對函數形參的名稱傳的
但是必須保證:
1.位置參數必須在關鍵字參數的前面(越短的越靠前,越長的越復雜的越靠后)
2.同一個形參不能被多次賦值
默認值參數
定義:在函數的定義階段,形參(變量名)就已經被賦值了
那么,在調用的時候可以不為默認值形參傳值,默認使用定義階段就已經綁定的值
在調用的時候如果可以給默認值形參傳值 傳了那么就使用你傳的值
在定義階段 默認值形參必須放在位置形參的后面
示例:
def my_max(x,y=100): if x > y: return x return y res = my_max(200) # 只給x傳一個值為200 res1 = my_max(200,1000) #給x傳一個值為200,給y傳一個值為1000(位置實參) res2 = my_max(y=200,x=1000) #給x傳一個值為200,給y傳一個值為1000(關鍵字實參) print(res2)
def register(username,age,gender='male'): #默認值為male print(username,age,gender) register('zhangsan',18) register('lisi',28) register('wangwu',84) register('maliu',58) register('xiaohong',17,'female') #如果為gender傳了參數,則用自己傳的參數
迷人小示例一(猜結果)
def info(username,hobby,l=[]): l.append(hobby) print('%s 的愛好是 %s'%(username,l)) info('zhangsan','學習') info('lisi','生蚝') info('wangwu','跑步') info('maliu','打拳')
答案
zhangsan 的愛好是 ['學習'] lisi 的愛好是 ['學習', '生蚝'] wangwu 的愛好是 ['學習', '生蚝', '跑步'] maliu 的愛好是 ['學習', '生蚝', '跑步', '打拳']
這時我們獲取的結果是錯誤的,有兩種解決辦法
第一種:
def info(username,hobby,l=[]): l.append(hobby) print('%s 的愛好是 %s'%(username,l)) info('zhangsan','學習',[]) info('lisi','生蚝',[]) info('wangwu','跑步',[]) info('maliu','打拳',[])
第二種:
def info(username,hobby,l=None): if l==None: l=[] l.append(hobby) print('%s 的愛好是 %s'%(username,l)) info('zhangsan','學習') info('lisi','生蚝') info('wangwu','跑步') info('maliu','打拳')
迷人小示例二:
m = 100 def my_max(x,y=m): print(x,y) m = 222 my_max(111)
答案
111 100
小總結:
函數在定義階段 內部所使用的變量都已經初始化完畢了,不會因為調用的位置的變化 而影響到內部的值
函數無論在什么地方被調用,都會跑到函數定義階段去執行代碼,形參中用到的值都是往函數定義階段代碼往上找
可變長參數
站在調用函數傳遞實參的角度,實參的個數不固定的情況,也就意味形參也不固定
站在形參的角度 可以用*和**來接收多余的(溢出的)位置參數和關鍵字參數
站在形參的角度 看 *
形參中的*會將多余的(溢出的)位置實參 統一用元組的形式處理 傳遞給*后面的形參名
def func(x,y,*z): print(x,y,z) # z = (3, 4, 5, 6, 7, 8, 54, 43, 4, 5, 6, 6, 7, 8) func(1,2,3,4,5,6,7,8,54,43,4,5,6,6,7,8,) #多余的實參會用元組去接收
站在實參的角度 看 *
# 如果要傳入一個列表,可以用*打散列表去傳值
def func(x,y,z): print(x,y,z) l = [1,2,3] a,b,c = l func(a,b,c) func(*[1,2,3,4,5,6]) # *會將列表打散成位置實參一一傳入等價於func(1,2,3,4,5,6) func(*(1,2,3)) # 等價於func(1,2,3) def func(x,*z): print(x,z) func(1,*{1,2,3}) # *在形參中只能接收多余的位置實參 不能接收關鍵字實參 # *只能將列表 元組 集合 字符串 # *的內部你可以看成是for循環
站在形參的角度看 **
def func(x,y,**z): print(x,y,z) # z = {'z': 1, 'a': 1, 'b': 2, 'c': 3} func(x=1,y=2,z=1,a=1,b=2,c=3) # **會接收所有多余的關鍵字參數 並將關鍵字參數 轉換成字典的形式 字典的key就是關鍵字的名字 # 字典的value就是關鍵字的名字指向的值 將字典交給**后面的變量名
站在實參的角度看 **
def func(x,y,z): print(x,y,z) func(12,3,4) func(x=1,y=2,z=3) d = {'x':1,'y':2,'z':333} func(x=1,y=2,z=3) func(**d) # 等價於func(x=1,y=2,z=333) # **會將字典拆封成 key = value的形式
總結:* 與 **
*在形參中能夠接受多余的位置參數 組織成一個元祖賦值給*后面的變量名
**在形參中能夠接受多余的關鍵字參數 組織成一個字典賦值給**后面的變量名
*:在實參中 *能夠將列表 元祖 集合 字符串 打散成位置實參的形式傳遞給函數(*就看成是for循環取值)
**:在實參中 能將字典打散成key = value的形式 按照關鍵字參數傳遞給函數
注意:python推薦形參*和**通用的寫法
def func2(*args,**kwargs): print(args,kwargs) func2(1,2,3,4,5,6,x=1,y=2,z = 3)
