一、函數是什么
函數一詞來源於數學,但編程中的「函數」概念,與數學中的函數是有很大不同的,編程中的函數在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子過程或子程序),在Pascal中叫做procedure(過程)和function,在C中只有function,在Java里面叫做method。
定義: 函數是指將一組語句的集合通過一個名字(函數名)封裝起來,要想執行這個函數,只需調用其函數名即可。
二、使用函數的好處
1、簡化代碼
2、提高代碼的復用性
3、代碼可擴展
三、python中函數的定義
定義函數使用def關鍵字,后面是函數名,函數名不能重復
def fun():#定義一個函數,后面是函數名
print("Hello World")#函數體
當然上面的函數其實沒有什么卵用,就是寫個函數定義的例子而已。
四、函數的參數
1、形參和實參
函數在調用的時候,可以傳入參數,有形參和實參,簡單點說,形參就是函數接收的參數,而實參就是你實際傳入的參數。
形參:形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。
實參:實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。函數調用結束返回主調用函數后則不能再使用該形參變量。
def calc(x,y):#定義一個函數,參數有x和y,x和y就是形參
print(x*y)#輸出x乘以y的值
calc(5,2)#調用上面定義的函數,5和2就是實參
2、函數的四種形參類型
(1)位置參數
位置參數,字面意思也就是按照參數的位置來進行傳參,有幾個位置參數在調用的時候就要傳幾個,否則就會報錯了。
# name,sex為位置參數/必填參數 def my(name,sex): print(name,sex) return name my('wwww','男')
(2)默認參數
默認參數就是在定義形參的時候,給函數默認賦一個值,比如說數據庫的端口這樣的,默認給它一個值,這樣就算你在調用的時候沒傳入這個參數,它也是有值的
# port=3306為默認值參數 def connect(ip,port=3306): print(ip,port) #如果給一個port值,則傳新給的值 connect('118.1.1.1',3307) #如果不填,則使用默認參數 connect('118.1.1.1')
(3)可變參數
1、可變參數用*來接收,不是必傳的;
2、它把傳入的元素全部都放到了一個元祖里;
3、不顯示參數個數,后面想傳多少個參數就傳多少個,它用在參數比較多的情況下
4、如果位置參數、默認值參數、可變參數一起使用的的話,可變參數必須在位置參數和默認值參數后面。
#實例:發送報警短信 參數前面加*代表參數組 def send_sms(*phone_num): #方法1,返回的是元祖 print(phone_num) #方法2,用下面循環的方法,不打印整個元祖,而是打印每一個元素 # for p in phone_num: # print(p) send_sms()# 不傳參數 send_sms(150)# 傳1個 send_sms(151,152,153)# 傳N個 # 執行后結果是: # () # (150,) # (151, 152, 153)
(4)關鍵字參數
1、關鍵字參數使用**來接收
2、返回的是字典
3、不限制參數個數,非必傳
4、當然也可以和上面的幾種一起來使用,如果要一起使用的話,關鍵字參數必須在最后面
def send_sms2(**phone_num): print(phone_num) send_sms2() send_sms2(name='xiaohei',sex='nan') send_sms2(addr='北京',country='中國',aa='hahaha') # 執行后結果是: # {} # {'name': 'xiaohei', 'sex': 'nan'} # {'addr': '北京', 'country': '中國', 'aa': 'hahaha'}
(5)以上四種放在一起使用
如果一定要一起用的話,要按下面的順序寫,不能換順序,否則會出錯
1、位置參數;2、默認值參數;3、可變參數;4、關鍵字參數
def my(name,country='china',*args,**kwargs): print(name) print(country) print(args) print(kwargs) # 看看都是誰接收到了誰 my('xiaohong','2','3','4','5',a='6',b='7')
五、函數的返回值-return語句
每個函數都有返回值,如果沒有在函數里面指定返回值的話,在python里面函數執行完之后,默認會返回一個None,函數也可以有多個返回值,如果有多個返回值的話,會把返回值都放到一個元組中,返回的是一個元組。
為什么要有返回值呢,是因為在這個函數操作完之后,它的結果在后面的程序里面需要用到。
函數中的返回值使用return,函數在遇到return就立即結束。
1、什么樣的函數需要returen,什么樣的不需要?下面這個只是顯示當前日期,就不需要return
import datetime def get_today(): print(datetime.datetime.today())
2、函數的返回值寫法
#只有一個返回值 def calc(x,y):#這個就是定義了一個有返回值的函數 c = x*y return c,x,y res = calc(5,6)#把函數的返回結果賦值給res print(res) # 當return有多個值時 def my3(): a=1 b=2 c=3 # a,b,c=1,2,3#也可以這樣寫 return a,b,c a,b,c=my3() s=my3() print(s) print(a,b,c) # 返回結果分別是 # (1, 2, 3) # 元祖 # 1 2 3 # int
3、returen的另一個作用
def my2(): for i in range(50): return i print(my2()) #我們以為會返回0~49,實際運行返回了0,這是因為 #return 有2個作用 # 1、結束函數,只要函數里面遇到return,函數立即結束運行 # 2、返回函數處理的結果
六、局部變量和全局變量
1、局部變量意思就是在局部生效的,出了這個變量的作用域,這個變量就失效了。
2、全局變量的意思就是在整個程序里面都生效的,在程序最前面定義的都是全局變量。
3、全局變量如果要在函數中修改的話,需要加global關鍵字聲明,如果是list、字典和集合的話,則不需要加global關鍵字,直接就可以修改。
4、任何函數都可以修改,所以盡量少用全局變量,原因1不夠安全。原因2全局變量一直占用內存.
#如果兩種變量都有,會先用局部變量,當沒有局部變量則用全局變量 #全局變量,在函數的外面 name='wangcan' def get_name(): # 聲明修改全局變量 global name # 局部變量,定義在函數內部 name='hailong' print('函數里面的name:'+name) def get_name2(): print('get_name2:',name) get_name2() #第一調用,打印wangcan get_name() #第二調用,打印函數內的name:hailong print('函數外面的name:'+name)# 最后打印,因為有函數聲明了全局變量,所以打印的是:hailong #最后的結果是 # get_name2: wangcan # 函數里面的name:hailong # 函數外面的name:hailong
七、遞歸調用
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
遞歸調用的意思就是,在這個函數內部自己調用自己,就有點循環的意思,寫個遞歸,如下:
#遞歸應用舉例 def test1(): num = int(input('please enter a number:')) if num%2==0:#判斷輸入的數字是不是偶數 return True #如果是偶數的話,程序就退出了,返回true print('不是偶數請重新輸入!') return test1()#如果不是偶數的話繼續調用自己,輸入值 print(test1())#調用test
遞歸調用的特性:
1. 必須有一個明確的結束條件
2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)
八、小練習:校驗小數類型
小練習:輸入一個字符串,判斷是否是小數
提示:
1、1.5小數點個數為1 '1.5'.count('.')==1
2、a.3小數點左邊和右邊都是整數,用點分隔 st.isdigit()
3、負小數 負號開頭並且只有一個負號 只有一個,什么開頭
def check_float(s): ''' 這個函數的作用就是判斷傳入的字符串是否合法的小數 :param s: 傳入一個字符串 :return: True/False ''' # 不管傳什么類型,先轉成字符換 s = str(s) #判斷小數點個數為1 if s.count('.')==1: # 用點分隔#-1.5 [-1.5] res = s.split('.') left,right=res if left.isdigit() and right.isdigit():# 判斷是否只由數字組成 # if res[0].isdigit() and res[1].isdigit():# 判斷是否只由數字組成,上面兩句也可以這樣寫 print('是小數') return True # 以負號開頭,並left中且第一個字符后面的都是整數(用到了切片),right是整數 elif left.startswith('-') and left[1:].isdigit() and right.isdigit(): # elif res[0].startswith('-') and res[0][1:].isdigit() and res[1].isdigit(): print('是小數') return True return False print(check_float('1.3')) print(check_float('-1.3')) print(check_float('---1.3')) print(check_float('a.3')) print(check_float('1..3'))