Python學習筆記整理Module2
三元運算
什麼是三元運算?
三元運算即三元表示式
三元表示式僅應用於:條件成立返回一個值不成立返回一個值.
示例:
a = 5 b = 7 if a < b: val = a else: val = b print(val)
示例:三元表示式寫法
val=a if a>b else b print(val)
檔案操作
檔案的基本處理形式
- 開啟檔案
- 操作檔案
- 關閉檔案
方法引數解析:
# 開啟檔案 f=open(r'檔案的路徑',mode='開啟檔案的模式',encoding='操作檔案的字元編碼') # 讀,寫 f.read() f.write('你好!!') #關閉檔案 f.close
檔案的開啟編碼格式:
- windows:gbk
- Linux:utf-8
開啟檔案的模式:r ,w , a ,b(不能單獨使用)
- r:只讀模式
- 當檔案不存在時報錯
- w:只寫模式
- 當檔案不存在時建立檔案,當檔案存在時清空原始檔
- a:加模式
- 當檔案不存在時建立檔案,當檔案存在時游標移動至檔案尾
檔案的操作模式
檔案的讀取
- 文字模式 ‘r'
- 二進位制模式’rb‘
file = open('file_test','r',encoding='utf-8') data = file.read() print(data) file.close()
file = open('file_test', 'rb') data = file.read() print(data) file.close()
檔案的迴圈讀取
file = open('file_test','r',encoding='utf-8') for lien in file: print(lien) file.close()
通過模組獲取該檔案的字元編碼
可使用python第三方工具chardet
安裝:
終端下輸入:C:\Users\67525>pip3 install chardet
Requirement already satisfied: chardet in d:\mypath\python36\lib\site-packages (3.0.4)
語法:
import chardet f = open('檔案操作筆記', 'rb') data = f.read() char = chardet.detect(data) print(char)
檔案的寫入
- 文字模式寫入
- 二進位制文字模式寫入
file = open('file_xie','w',encoding='utf-8') file.write('你好!!') file.close()
file = open('file_xie', 'wb') file.write('你好'.encode('utf-8')) file.close()
檔案的追加寫入
- 文字追加寫入
- 二進位制追加寫入
file = open('file_xie','a',encoding='utf-8') file.write('\tworld!') file.close()
file = open('file_xie','ab') file.write('\n人生苦短,我用Python!!'.encode('utf-8')) file.close()
混合操作模式(可讀寫)
file = open('file_xie','w+',encoding='utf-8') file.write('\n你好 世界!') data = file.read() print(data) file.close()
其他的混合模式w+ ,a+,wb+,ab+,rb+
檔案的拷貝
import sys l=sys.argv # 把命令列中直譯器後空格分割的所有引數都存成列表 # print(l) src_file_path=l[1] dst_file_path=l[2] # print(src_file_path) # print(dst_file_path) with open(r'%s' %src_file_path,mode='rb') as src_f,\ open(r'%s' %dst_file_path,mode='wb') as dst_f: for line in src_f: dst_f.write(line)
檔案都修改
- 通過硬碟修改
- 通過記憶體修改
import os old_name = 'test' new_name = 'new_%s'%old_name old_str = '月' new_str = '日' old_file = open(old_name,'r',encoding='utf-8') new_file = open(new_name,'w',encoding='utf-8') for lien in old_file: if old_str in lien: lien = lien.replace(old_str,new_str) print(lien) new_file.write(lien) old_file.close() new_file.close() os.replace(new_name, old_name)
函式
函式的定義
什麼是函式?
函式即在具備某一個功能的子程式。
為什麼要有函式?
解決以下問題:
- 組織結構不清晰,可讀性差
- 程式碼冗餘
- 管理維護的難度大,擴充套件性差
函式使用必須遵守的原則:必須先定義後使用。
語法
def 函式名(): """ 文件描述 """ 程式碼塊
定義函式的三種方式
1.有參函式:引數是函式程式碼需要在呼叫時傳入引數
def max(x,y): if x > y: return x else: return y
2.無參函式:函式在呼叫時無需傳入引數
def sayshi(): print("hello world!!")
3.空函式:即函式體程式碼塊內容為pass
def func(): pass
函式的呼叫
如何呼叫函式?
函式名加括號即可呼叫函式
def func(x,y):
print(x,y)
func(2,3)
呼叫函式時需知一下幾點
- 函式在呼叫前必須先定義函式,否則就相當於呼叫一個不存在的變數
- 定義階段:只檢測語法,不執行函式體程式碼.
- 呼叫階段:根據函式名找到對應的記憶體地址繼而執行函式體內的程式碼.
函式呼叫的三種方式:
定義函式:
def max(x,y): if x > y: print(x) else: print(y)
呼叫方式1.:
max(10,20)
呼叫方式2:
#2.1
res = max(10,20) print(res)
#2.2 res = max(10,20)*10 print(res)
呼叫方式3:
def max(x,y): if x > y: return x else: return y res = max(max(10,20),30) print(res)
返回值
為何要有返回值?什麼是返回值?
在函式執行結束後,需要返回一個結果給呼叫者,返回的結果即返回值
取返回值可以使用return.
- 返回值沒有型別限制.
- 當函式中出現return則代表函式的結束,函式中可以出現多個return但只返回第一個return的返回值且不會執行return後面的程式碼
返回值得三種種狀態:
- 無返回值:則使用預設的返回值None
def func(): print('hello') res = func() print(res)
- 返回一個值:則返回return後面的值
def func2(x,y): s = x+y return s res = func2(1,2) print(res)
- 返回多個值:返回多個值以逗號分隔,以元組的形式返回
def func3(): return 1,2,3,4 res = func3() print(res)
引數
什麼是形參?什麼是實參?
形參即形式引數:在函式定義時,括號內的引數
實參即實際引數:在函式呼叫時,括號內傳入的引數
補充:形參與實參只在函式呼叫時繫結關係,在函式結束後則失去繫結關係。
位置引數:
按照順序定義的引數,可分為位置形參與位置實參
- 位置形參即在函式定義時,括號內定義的引數
- 位置實現即在函式呼叫時,括號內傳入的引數
# 這裡是位置形參 def foo(x,y,z): print(x,y,z) #這裡是位置實參 foo(1,2,3)
關鍵字引數
關鍵字引數即以key-value的傳入的引數稱為關鍵字實參。
- 關鍵字引數相當於以指名道姓的形式為其傳參,這便意味著即使不按照順序定義,依然能為其傳參。
- 關鍵字引數可以與位置引數混合使用,但必須在預設引數後為其傳參
示例:定義函式
def foo(x,y,z): print(x,y,z)
示例:呼叫函式(傳參)
foo(x=1,z=3,y=2)
混合使用:
foo(1,z=3,y=2)
錯誤示範:
1.缺少引數
foo(1,z=3)
2.為某個引數傳入多個值
foo(1,x=1,z=3,y=2)
預設引數
預設引數:即在函式定義時以為其指定值在函式呼叫時無需傳入引數。
- 在函式呼叫時如果傳入引數則使用傳入的值,否則使用預設值。
- 在傳入引數時,預設引數必須在位置引數的後面
- 預設引數的值應該設定為不可變型別
- 預設引數在函式定義時即固定了,所以無法修改
預設引數的應用:在大多時候一個引數不需要經常變更的時候可以使用預設形參,反正使用位置形參
示例:定義函式
def stu_register(name,age,course,country='CN'): print('姓名:',name) print('年齡:',age) print('課程:',course) print('國籍',country)
使用預設引數:
stu_register('zhansan',18,'Linux')
為預設引數傳入值:
stu_register('半藏',18,'python','JP')
可變長度的引數
什麼的可變長讀的引數?
可變長度的引數即函式的實參個數不固定,實參可以是位置實參或者是關鍵字實參
def func(name,*args,**kwargs): print(name,args,kwargs)
- *args接收的是位置引數,接收到的引數會以元組的形式賦值給args
- **kwargs接收的是關鍵字引數,接收到的引數會以字典的形式賦值給kwargs
引數的傳入,如果不傳入引數接收到的值即為空
func('zxx',18,addr='sx')
如果在實參中的*與**則會吧引數實參中的集合打散
func('zxx',*'123434343',**{'a':1,'b':2}) #執行結果為:zxx ('1', '2', '3', '4', '3', '4', '3', '4', '3') {'a': 1, 'b': 2}
函式的巢狀使用
什麼是函式的巢狀?
函式的巢狀定義:即在函式定義在該函式內又定義了其他函式.
函式的巢狀呼叫:即在函式呼叫時在該函式內又呼叫了其他函式.
示例:巢狀定義
#! -*- coding:utf-8 -*- def func1(): print('from func1') def func2(): print('from f2') func2()
示例:函式的巢狀呼叫
def max1(x,y): if x > y: return x else: return y def max2(x,y,z): res1 = max1(x,y) res2 = max(res1,z) return res2 print(max2(15,9,13))
名稱空間與作用域
什麼的名稱空間?什麼是作用域?
名稱空間即:存放名字與繫結關係的地方.
名稱空間可以分為三類:
- 內建名稱空間.:用來存放python直譯器自帶的名字,在python直譯器啟動時生效,直譯器關閉則失效
- 全域性名稱空間:檔案級別的名字,在檔案啟動時生效,在檔案關閉時失效(可以在檔案執行時刪除,刪除即代表失效)
- 區域性名稱空間:存放函式內定義的名字(如,函式的引數)在函式被呼叫時生效函式結束則失效
名稱空間的載入順序:內建名稱空間----> 全域性名稱空間 ---->區域性名稱空間
名稱空間的查詢順序:區域性名稱空間(當前)--->全域性名稱空間 --->內建名稱空間
限定以名字的程式碼可用範圍這個名字即作用域
作用域可分為兩類:
- 全域性作用域:全域性生效的作用域。
- 在任何順序都能查詢到
- 生命週期長
- 區域性作用域:只在區域性生效(函式內部)的作用域
- 只在函式內部使用
- 函式結束則該作用域失效
作用域的查詢順序:LEGB
- L:LOCALS 函式內的名稱空間
- E:enclosing:上一級的名稱空間
- G:global:全域性名稱空間
- B:builtins:內建名稱空間
函式物件:
函式為python中的第一類物件:
- 可以被引用
- 可以作為實參引數傳給某個形參.
- 可以作為返回值
- 可以作為容器元素
示例:1
def func(): print("函式可被引用") # func即:函式func的記憶體地址 f = func f()
示例2:
def func1(): print("from func1") def func2(f): print(f"from {f}") func2(func1)
示例3:
def max(x,y): if x > y: return x else: return y res = max(5,10) print(res)
示例4:
def op_gt(): pass def op_lt(): pass def op_eq(): pass op = { '>':op_gt, '<':op_lt, '=':op_eq }
閉包函式
什麼是閉包函式?
閉:即定義在內部的東西。
閉包函式:即定義在函式內部的函式,並且該函式對外部函式作用域中的名字純在引用關係.
閉包函式的兩種形式:
示例1:第一種為國定值
def outer(): name = 'Myuan' def inner(): print(f'hello,{name}') inner() outer()
示例2:第二種通過引數傳入使值更加靈活
def outer(name): def inner(): print(f'hello,{name}') inner() outer('Myuan')
裝飾器
什麼是裝飾器?裝飾器又有什麼作用?
裝飾器即在不修改被裝飾物件的原始碼與呼叫方式的前提下為其新增新的功能。
裝飾器的作用即:在遵循開放封閉原則的前提下為其新增新功能
開放封閉原則:即對新增新功能的程式原始碼是封閉的而對其擴充套件性是開放的.
示例:無參裝飾器
def outer(func): def inner(*args,**kwargs): res = func(*args,**kwargs) return res return inner()
裝飾器語法糖:應該在被裝飾物件上單獨一行寫
import time # 這是裝飾器 def outer(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) stop_time = time.time() print(stop_time-start_time) return res return inner # 這是被裝飾物件 @outer def index(): time.sleep(3) print("welcome index page...") index()
裝飾器的使用例項:登入認證
import time current_user={ 'username':None, # 'login_time':None } def auth(func): # func=index def wrapper(*args,**kwargs): if current_user['username']: print('已經登陸過了') res=func(*args,**kwargs) return res uname=input('使用者名稱>>: ').strip() pwd=input('密碼>>: ').strip() if uname == 'egon' and pwd == '123': print('登陸成功') current_user['username']=uname res=func(*args,**kwargs) return res else: print('使用者名稱或密碼錯誤') return wrapper @auth #index=auth(index) def index(): time.sleep(1) print('welcome to index page') return 122
有參裝飾器
有參裝飾器即帶有引數的裝飾器
例子:
import time current_user={ 'username':None, # 'login_time':None } def auth(engine): # engine='file' def auth2(func): # func=index def wrapper(*args,**kwargs): if engine == 'file': if current_user['username']: print('已經登陸過了') res=func(*args,**kwargs) return res uname=input('使用者名稱>>: ').strip() pwd=input('密碼>>: ').strip() if uname == 'egon' and pwd == '123': print('登陸成功') current_user['username']=uname res=func(*args,**kwargs) return res else: print('使用者名稱或密碼錯誤') elif engine == 'mysql': print('基於MyQL的認證') elif engine == 'ldap': print('基於LDAP的認證') return wrapper return auth2 @auth('ldap') #@auth2 #index=auth2(index) #index=wrapper def index(): time.sleep(1) print('welcome to index page') return 122 index() # wrapper()
迭代器
什麼是可迭代物件?什麼是迭代器?
可迭代物件即有內建方法_iter_方法的物件
迭代器物件即可迭代物件執行_iter_方法返回後的結果.
迭代器物件的優缺點:
- 提供了一種不依賴索引的取值方式,更加節省記憶體空間
- 取值麻煩,只能依次取值,並且是一次性的.
可迭代物件與迭代器物件:
- python內建str,list,tuple,dict,set,file都是可迭代物件
- 可迭代物件執行_inter_後返回的結果就是迭代器物件
示例:字串為例
s = 'hello world' res = s.__iter__() print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__())
擴充套件知識點:
for迴圈又被稱為迭代器迴圈,使用in 後面必須跟一個可迭代物件.
生成器
什麼是生成器?
如果一個函式中包含yield關鍵字,在呼叫函式時不會yield關鍵字後面的的程式碼,而拿到的返回值就是一個生成器.
擴充套件點:
生成器本身就是一個迭代器,生成器具有迭代器的特性
生成器的yield關鍵字:
必須初始化,send方法與next方法功能一致,區別是send方法可以給生成器傳值。
示例:
def eat(name): print('%s ready to eat' %name) food_list=[] while True: food=yield food_list # food='骨頭' food_list.append(food) #food_list=['泔水','骨頭'] print('%s start to eat %s' %(name,food)) dog1=eat('zxx') res1=dog1.send('饅頭') print(res1) res2=dog1.send('包子') print(res2)
列表生成式
列表生成式即生成列表的表示式。
例子:
l = [i+1 for i in range(10)]
函式的遞迴呼叫
什麼是遞迴函式?
遞迴函式即函式呼叫的過程中直接或間接的呼叫自身.
示例:直接呼叫
def func(): print('func') func() func()
示例:間接呼叫
def bar(): print('from bar') foo() def foo(): print('from foo') bar() foo()
函式的遞迴次數是有限制的可以使用sys模組檢視或修改
import sys # 檢視 print(sys.getrecursionlimit()) # 修改 sys.setrecursionlimit(1500)
遞迴分為兩個階段:
- 回溯:在使用歸回時必須賦予一個結束條件,否則無限遞迴
- 遞推
在使用遞迴時必須明確
- 必須明確一個結束條件
- 沒遞迴一次,遞迴的問題必須減少
- 在Python中沒有尾遞迴優化
遞迴應用例項:斐波那契數列
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done' fib(10)
匿名函式
匿名函式即沒有名字的函式。
定義一個匿名函式使用lambda關鍵字。匿名函式的函式體一個是一個表示式,該表示式必須要有一個返回值
例子:
numbers = list(range(1, 10)) # print(numbers) print(list(map(lambda x:x*x,numbers)))
應用場景:一般與某些特定的方法配合使用
Python內建函式
內建函式的詳細介紹:https://docs.python.org/3/library/functions.html?highlight=built#ascii
模組
什麼是模組?
模組即一個功能的集合,在python中一個python檔案就是一個模組
模組的匯入
- import
- form ...import
- from .. import as ..
模組的匯入過程:
- 建立一個名稱空間
- 執行模組的對應檔案並將產生的名字放入建立好的名稱空間中
- 在當前執行檔案中拿到該模組名,並將該模組名指向以對應的模組名稱空間中
示例:匯入模組
import time
示例:只想使用某個模組的某個功能時
from tabulate import tabulate
示例:為模組起別名
from tabulate import tabulate as tab
模組的搜尋路徑
模組的查詢順序:
- 記憶體中以載入的模組
- 內建模組
- sys.path路徑中包含的模組
補充
sys.path中第一個搜尋路徑是執行檔案的當前路徑
包的匯入
什麼是包?
包即資料夾。當你的模組檔案越來越多,就需要對模組檔案進行劃分,比如把負責跟資料庫互動的都放一個資料夾,把與頁面互動相關的放一個資料夾
匯入包的過程:
- 產生一個該包的名稱空間
- 執行包下的_init_檔案,並將參生的名字存放於該包的名稱空間中
- 在當前執行檔案中拿到一個名字,將該名字指向包的名稱空間中