一、函數
函數的基礎概念:
函數是python為了代碼最大程度地重用和最小化代碼冗余而提供的基本結構
函數是一種設計工具,它能讓程序員將復雜的系統分解為可管理的部件
函數用於將相關功能打包並參數化
在python中可以創建4種函數
(1)全局函數:定義在模塊
(2)局部函數:嵌套於其它函數中
(3)lambda函數:表達式,如需多次調用
(4)方法:與特定數據類型關聯的函數,並且只能與數據類型關聯一起使用
python提供了很多內置函數
創建函數:
def functionName(arg1,arg2,...): suite return
函數的定義主要有如下要點:
- def:表示函數的關鍵字
- 函數名:函數的名稱,日后根據函數名調用函數
- 函數體:函數中進行一系列的邏輯計算,如:發送郵件、計算出 [11,22,38,888,2]中的最大數等...
- 參數:為函數體提供數據
- 返回值:當函數執行完畢后,可以給調用者返回數據。
一些相關的概念:
def是一個可執行語句
因此可以出現在任何能夠使用語句的地方,甚至可以嵌套於其他語句,例如if或while中
def創建了一個對象並將其賦值給一個變量名(即函數名),函數體則存在內存
return用於返回結果對象,其為可選;無return語句的函數自動返回None對象
返回多個值時,彼此間使用逗號分隔,且組合為元組形式返回一個對象
函數一旦執行到return,函數就終止了,如果return下面還有執行語句則終止
def語句運行之后,可以在程序中通過函數后附加()進行調用
函數作用域:
python創建、改變或查找變量名都是在名稱空間中進行
在代碼中變量名被賦值的位置決定了其能被訪問到的范圍
函數定義了本地作用域,而模塊定義了全局作用域
1.全局變量全部用大寫表示
2.全局變量都可以被訪問,函數內部的變量則為本地作用域
3.在函數內如果要修改全局變量,需要global
4.特殊:字典,列表可以在函數內修改,但是不能重新賦值
更多作用域
NAME = 'tomcat' def f1(): age = 18 global NAME NAME = 'xiao' print(age,NAME) def f2(): age = 27 print(age,NAME) f1() f2()
函數的參數:
默認情況下,參數通過其位置進行傳遞,從左至右,這意味着,必須精確地傳遞和函數頭部參數一樣多的參數
但也可以通過關鍵字參數、默認參數或參數容器等改變這種機制
(1)普通參數:定義函數時從左至右
(2)默認參數:定義函數時是使用"name=value"的語法直接給變量一個值,從而傳入的值可以少於參數個數
(3)指定參數:調用函數時指定"name形式參數=value實際參數"的語法通過參數名進行匹配
(4)動態參數:定義函數時形式參數中收集任意多基於普通參數
定義函數時使用* :收集普通參數,返回元組,*args
定義函數時使用**:收集指定參數,返回列表,**kwargs
(5)動態參數解包:調用函數時,使用**開頭的參數,從而傳遞任意多基於普通或指定參數
注意:定義函數時
1.混用普通參數和默認參數,應當把默認參數寫到右側
2.混用有默認和無默認值的參數時,無默認值放左側
1、返回值
函數是一個功能塊,該功能到底執行成功與否,需要通過返回值來告知調用者。
以上要點中,比較重要有參數和返回值:
def 發送短信(): 發送短信的代碼... if 發送成功: return True else: return False while True: # 每次執行發送短信函數,都會將返回值自動賦值給result # 之后,可以根據result來寫日志,或重發等操作 result = 發送短信() if result == False: 記錄日志,短信發送失敗...
2、參數
沒有參數的情況
#!/usr/bin/env python # -*- coding:utf-8 -*- ''' 1.需要開啟郵箱服務sendmail 2.郵箱服務器需要開啟SMTP服務 ''' def sendmail(): try: import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('郵件內容', 'plain', 'utf-8') msg['From'] = formataddr(["發件人", 'pythonxiao@126.com']) msg['To'] = formataddr(["收件人", '329275108@qq.com']) msg['Subject'] = "郵件主題" server = smtplib.SMTP("smtp.126.com", 25) server.login("pythonxiao@126.com", "xiaozhiqi2016") server.sendmail('pythonxiao@126.com', ['329275108@qq.com', ], msg.as_string()) server.quit() except: return False else: return True ret = sendmail() if ret == True: print("發送成功") else: print("發送失敗")
有參數的情況:
#!/usr/bin/env python # -*- coding:utf-8 -*- def sendmail(email,content): try: import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText(content, 'plain', 'utf-8') msg['From'] = formataddr(["發件人", 'pythonxiao@126.com']) msg['To'] = formataddr(["收件人", '329275108@qq.com']) msg['Subject'] = "郵件主題" server = smtplib.SMTP("smtp.126.com", 25) server.login("pythonxiao@126.com", "xiaozhiqi2016") server.sendmail('pythonxiao@126.com', [email, ], msg.as_string()) server.quit() except: return "失敗" else: return 'cc' while True: msg = input("請輸入郵箱地址:") #實際參數 ret = sendmail(msg,"SB") if ret == 'cc': print("發送成功") break else: print("發送失敗")
從上面例子可以看出有參數的函數表現的非常靈活可擴展!
函數的有三中不同的參數(定義函數時):
- 普通參數
- 默認參數
- 動態參數
指定參數和動態參數解包是發生在調用函數

(1)# xxoo為普通參數也叫形式參數,簡稱:形參 def f1(name): print(name) # 'test' 叫做函數的實際參數,簡稱:實參 f1('tomcat')

(2)# name 是普通參數,ab=5是默認參數 def f1(name,ab=5): print(name,ab) # 指定參數 f1('tomcat',12) # 使用默認參數 f1('tomcat') 注意:默認參數需要放在參數列表最后

(3)# 動態參數(1):*args 返回的是一個元組 def f1(*args): print(args,type(args)) # 執行方式一 f1(11) # 如果傳入一個列表,則這個列表是當作元組中的一個元素 li = ['a','b','c'] f1(li) # 執行方式二:執行函數時有*,把所有迭代對象拆分為單個元素作為元組的元素,如傳入列表,會把列表中每一個元素遍歷添加到元組中當作一個元素 f1(*l1)

(4)#動態參數(2):**kwargs 返回的是一個字典 def f1(**kwargs): print(args,type(args)) # 執行方式一:只能傳入指定參數 f1(n1='alex',n2=18) dic = {'k1':'v1','k2':'v2'} f1(kk=dic) # 執行方式二:實際參數如果有**,傳入的應該是一個字典,會把每一對鍵值對像不帶**一樣把指定參數傳入函數中 f1(**dic)

(5)# 俗稱萬能參數 def f1(*args,**kwargs): print(args,type(args)) print(kwargs,type(kwargs)) # 執行方式一 f1(11,22,33,k1='v1',k2='v2') # 執行方式二 l1 = [1,2,3,4] d1 = {'a':'xiao','b':'zhi','c':'qi'} f1(*l1,**d1)
在python中可以經常看到萬能參數,比如str.format()用於格式化的方法,這里用不同的參數傳遞方式實現相同的效果
>>> s1 = 'i am {0}, age {1}'.format('alex',18) >>> print(s1) i am alex, age 18 >>> s2 = 'i am {0}, age {1}'.format(*['alex',18]) >>> print(s2) i am alex, age 18 >>> s3 = 'i am {0}, age {1}'.format(*('alex',18)) >>> print(s3) i am alex, age 18 >>> s4 = 'i am {name}, age {age}'.format(name='alex',age=18) >>> print(s4) i am alex, age 18 >>> dic = {'name':'alex','age':18} >>> s5 = 'i am {name}, age {age}'.format(**dic) >>> print(s5) i am alex, age 18
3.補充:
(1).在定義相同函數時,后一個函數名會指向新的內存對象,函數名是函數體在內存中的引用,就像變量賦值一樣,變量名是對對象在內存中的引用
def f1(a,b): return a + b def f1(a,b): return a * b ret = f1(8,8) print(ret)
(2).函數在傳遞參數的時候是內存中的引用,而不是復制,所以l1的值是[1,2,3,4,999]
def f1(a1): a1.append(999) l1 = [1,2,3,4] f1(l1) print(l1)
稍微改變下,用一個變量來接收函數的返回值,這里的l1的值不是[1,2,3,4,999],而是None,因為函數內並沒有定義返回值,所以為None
def f1(a1): a1.append(999) l1 = [1,2,3,4] l1 = f1(l1) print(l1)
函數式編程:
以后寫函數按照下面這個例子來編寫,規范,這是一個登錄注冊的函數編程
1.函數與函數間隔2行
2.函數需要注釋,便於記憶
3.函數名需要見名知意
db文件格式

admin|123
xiao|12345
代碼
#!/usr/bin/env python # coding: utf8 def datainput(): username = input("input your username:") password = input("input your password:") return username,password def login(username,password): f = open('db','r') for line in f: data = line.strip().split('|') if data[0] == username and data[1] == password: return True return False def register(username,password): f = open('db','r') for line in f: user = line.strip().split('|') #print(user) if username in user: return False else: f = open('db','a') userdata = "\n" + username + "|" + password f.write(userdata) f.close() return True def main(): num = input("1.登錄,2.注冊:") if int(num) == 1: data = datainput() result = login(data[0],data[1]) if result: print('登錄成功') else: print('登錄失敗') elif int(num) == 2: data = datainput() ret = register(data[0],data[1]) if ret: print("注冊成功") else: print("注冊失敗,用戶已存在") main()
二、三元運算符
三元表達式,三元運算,三目運算符都是指同一個意思:可以簡化條件語句的縮寫,可以使代碼看起來更加簡潔,三目可以簡單的理解為有三個變量,它的形式是這樣的 name= k1 if 條件 else k2 ,如果條件成立,則 name=k1,否則name=k2,下面從代碼里面來加深一下理解,從下面的代碼明顯可以看出三目運算符可以使代碼更加簡潔。
a=1 b=2 if a<b: #一般條件語句的寫法 k=a else: k=b c=a if a<b else b #三目運算符的寫法,如果a<b為True,則c=a,否則c=b
三、lambda表達式
對於簡單的函數,也存在一種簡便的表示方式,即:lambda表達式
# ###################### 普通函數 ###################### # 定義函數(普通方式) def func(arg): return arg + 1 # 執行函數 result = func(123) # ###################### lambda ###################### # 定義函數(lambda表達式) my_lambda = lambda arg : arg + 1 # 執行函數 result = my_lambda(123)
lambda表達式會自動return返回值,條件為真返回True,條件為假返回False.
四、遞歸
如果一個函數在其內部調用它自己,就叫做遞歸,但是遞歸的時候要設置一個退出遞歸的條件,不然會一直遞歸下去,變成一個死循環。從另一個方面來說,遞歸其實和循環其實是等價的。想要明白遞歸的話,我們先從實際的例子上來說明這一點,比如說我們要寫一個階乘函數 f(n)算出n的階乘,階乘函數實現的方法很多,下面講如何用遞歸實現
def f(n): if 0==n: # n=0 的話直接返回空,對用戶輸入的零進行判斷 return None elif 1==n: # n=1 的話就不再遞歸 return n else: return n*f(n-1) # 遞歸在執行f(n-1) 直到f(1) print(f(5)) # 120 ''' f(5)的執行過程如下 ===> f(5) ===> 5 * f(4) ===> 5 * (4 * f(3)) ===> 5 * (4 * (3 * f(2))) ===> 5 * (4 * (3 * (2 * f(1)))) ===> 5 * (4 * (3 * (2 * 1))) ===> 5 * (4 * (3 * 2)) ===> 5 * (4 * 6) ===> 5 * 24 ===> 120 '''
再來一個例子:
def func(n): n += 1 if n >= 4: return 'end' return func(n) r = func(4) print(r)
end #這是執行結果
下面的圖幫助理解
傳入1的時候,n=2不滿足n>=4這個條件,return func(2)
傳入2的時候,n=3不滿足n>=4這個條件,return func(3)
傳入3的時候,n=4滿足n>=4這個條件,return end
return end --> return func(3) --> return func(2) --> r = func(1) 所以r的返回值就是end
練習:
1、寫函數,計算傳入字符串中【數字】、【字母】、【空格] 以及 【其他】的個數
def fun(s): digitnum, alphanum, sapcenum, othernum=0,0,0,0 for i in s: if i.isdigit(): digitnum+=1 elif i.isalpha(): alphanum+=1 elif i.isspace(): sapcenum+=1 else: othernum+=1 return (digitnum,alphanum,sapcenum,othernum)
2、寫函數,判斷用戶傳入的對象(字符串、列表、元組)長度是否大於5
def fun(s): ret=False if isinstance(s,str) or isinstance(s,str) or isinstance(s,tuple): if len(s)>5: ret=True return ret
3、寫函數,檢查用戶傳入的對象(字符串、列表、元組)的每一個元素是否含有空內容
def fun(s): ret=False if isinstance(s, str) or isinstance(s, str) or isinstance(s, tuple): for i in s: if i=='': ret=True break return ret
4、寫函數,檢查傳入列表的長度,如果大於2,那么僅保留前兩個長度的內容,並將新內容返回給調用者。
def fun(s): if isinstance(s,list): if len(s)>2: return s[0:2] return None
5、寫函數,檢查獲取傳入列表或元組對象的所有奇數位索引對應的元素,並將其作為新列表返回給調用者。
def fun(s): if isinstance(s,list) or isinstance(s,tuple): l=[] for i in range(1,len(s),2): l.append(s[i]) return l return None
6、寫函數,檢查傳入字典的每一個value的長度,如果大於2,那么僅保留前兩個長度的內容,並將新內容返回給調用者。
def fun(s): if isinstance(s,dict): for i in s: if len(s[i])>2: s[i]=s[i][0:2] return s
7、寫函數,利用遞歸獲取斐波那契數列中的第 10 個數,並將該值返回給調用者。
def fun(n): if 1==n : return 0 elif 2==n: return 1 else: return fun(n-1)+fun(n-2)