目錄
模塊(Module)
定義
包含一系列數據、函數、類的文件,通常以.py結尾
作用
讓一些相關的代碼,有邏輯的組織在一起,使結構更加清晰。
導入
【1】import
- 語法:import 模塊名 [as 別名]
- 作用:將某個模塊整體導入到當前模塊
- 本質:使用變量名(模塊名)關聯指定模塊代碼。
- 使用:模塊名.成員
- 導入方式:
導入模塊名稱
本質:將該模塊作用域賦值給變量module01
import module01
module01.fun01()#調用module01中的函數
c01 = module01.MyClass01()#調用module01中的類
c01.fun02()#調用類中的方法
【2】from import
- 語法:from 模塊名 import 成員 [as 別名]
- 作用:將模塊內的一個或多個成員導入到當前模塊的作用域中。
- 使用:成員
- 導入方式:
本質:將該模塊指定成員賦值給變量fun01,MyClass01
from module01 import fun01,MyClass01
fun01()
c01 = MyClass01()
c01.fun02()
【3】from import *
- 語法:from 模塊名 import *
- 作用:將某模塊的所有成員導入到當前模塊
- 模塊中以單下劃線(_)開頭的屬性,不會被導入,通常稱這些成員爲隱藏成員
- 導入方式:
from module01 import *
fun01()
c01 = MyClass01()
c01.fun02()
模塊變量
__all__變量:定義可導出成員,僅對from xx import * 語句有效
# 只能導出該模塊中的fun01()和class MyClass01
__all__ = ["fun01", "MyClass01"]
__doc__變量:文檔字符串。(獲取模塊文檔註釋 “”" 註釋 “”")
import module01
print(module01.__doc__)
__file__變量:模塊對應的文件路徑名
print(module01.__doc__)
__name__變量:模塊自身名字,可以判斷是否爲主模塊。當此模塊作爲主模塊(第一個運行的模塊)運行時,__name__綁定’__main__’,不是主模塊,而是被其他模塊導入時,存儲模塊名。
# 獲取模塊名稱
print(module01.__name__) # module01 & __main__
if __name__ == "__main__": # 如果程序從當前模塊運行,則執行下列的測試代碼;如果當前模塊被主模塊導入,則下列測試代碼不再執行
加載過程
在模塊導入時,模塊的所有語句都會執行。
如果一個模塊已經導入,則再次導入時不再重複執行語句。
分類
- 內置模塊(builtins):在解釋器的內部可以直接使用。
- 標準庫模塊:安裝python時自帶的,經過導入後可直接使用。
e.g. 標準庫模塊——時間(time)
import time
# 返回時間戳(1970年後經過的浮點秒數)
print(time.time())
# 時間戳-->時間元祖(年 月 日 時 分 秒 星期 一年的第幾天 夏令時)
print(time.localtime(1586232291.0553486)) #time.struct_time(tm_year=2020, tm_mon=4, tm_mday=7, tm_hour=12, tm_min=4, tm_sec=51, tm_wday=1, tm_yday=98, tm_isdst=0)
# 時間元祖-->時間戳
print(time.mktime(time.localtime()))
# 時間元祖-->字符串(時間的格式化)
print(time.strftime("%Y %m %d %H:%M:%S",time.localtime()))
# 字符串-->時間元祖
print(time.strptime("2019 04 18","%Y %m %d"))
- 第三方模塊(通常開源):需要自行下載安裝,再導入使用。
- 自定義模塊:用戶自己編寫的模塊,經過導入後可直接使用。
搜索順序
搜索內建模塊(builtins)
sys.path提供的路徑,通常第一個是程序運行時的路徑
# 列表,存儲的是解釋器導入模塊時搜索的路徑,可以通過append手動添加路徑
print(sys.path)
包(package)
定義
將模塊以文件夾的形式進行分組管理。
作用
讓一些相關的模塊組織在一起,使邏輯結構更加清晰。
導入
對應項目文件夾(比如:day14)–Mark Directory as–Sourcces Root
- 方式1:import 包.模塊
import package01.module01
# 使用包.模塊.成員
package01.module01.fun01()
- 方式2:from 包 import 模塊
from package01 import module01
# 使用:模塊.成員
module01.fun01()
- 方式3:from 包 import *
from package01 import *
# 在包的__init__.py文件中,定義__all__屬性(__all__=["module01"])
module01.fun01()
- 方式4【推薦】:from 包.模塊 import 成員
from package01.module01 import *
fun01()
注意:無論哪個文件都從根目錄開始寫起(導入)
異常處理(Error)
異常
- 定義:運行時檢測到的錯誤。
- 現象:當異常發生時,程序不再向下繼續執行,而轉到函數的調用語句。
- 常見異常類型:
- 名稱異常(NameError):變量未定義
- 數值異常(ValueError):值錯誤
- 類型異常(TypeError):不同類型數據進行運算
- 索引異常(IndexError):超出索引範圍
- 屬性異常(AttributeError):對象沒有對應名稱的屬性
- 鍵異常(KeyError):沒有對應名稱的鍵
- 未實現異常(NotImplementedError):尚未實現的方法
- 異常基類Exception
處理
- 語法:
try:
可能觸發異常的語句
except 錯誤類型1 [as 變量1]:
處理語句1
except 錯誤類型2 [as 變量2]:
處理語句2
except Exception [as 變量3]:
不是以上錯誤類型的處理語句
else:
未發生異常的語句
finally:
無論是否異常,一定執行的代碼
- 作用:將程序由異常狀態轉換爲正常流程
- 說明:
- as子句是用於綁定錯誤對象的變量,可以省略
- except子句可以有一個或者多個,用來捕獲某種類型的錯誤
- else子句最多隻能有一個
- finally子句最多隻能有一個,如果沒有except子句,必須存在。
- 如果異常沒有被捕獲到,會向上層(調用處)繼續傳遞,直到程序終止運行。
raise語句
- 作用:拋出一個錯誤,讓程序進入異常狀態。
- 目的:在程序調用層數較深時,向主程序傳遞錯誤信息要層層return比較麻煩,所以建議人爲拋出異常,可以直接傳遞錯誤信息。
自定義異常
- 定義
class 類名Error(Exception):
def __init__(self, 參數):
super().__init__(參數)
self.數據 = 參數
e.g. 自定義異常
class AgeError(Exception):
"""
封裝錯誤信息
"""
def __init__(self,msg,code,age_value):
super().__init__(msg)
self.msg = msg
self.code = code
self.age_value = age_value
- 調用
try:
...
raise 自定義異常類名(參數)
...
except 定義異常類 as 變量名:
變量名.數據
e.g.
# raise AgeError("我不要",27,value)
try:
w01 = Wife(80)
print(w01.age)
except AgeError as e:
print("錯誤信息:", e.msg)
print("錯誤代碼行號:", e.code)
print("輸入的年齡是", e.age_value)
- 作用:封裝錯誤信息
迭代(瞭解)
每一次對過程的重複稱之爲一次”迭代”,而每一次迭代得到的結果會作爲下一次迭代的初始值。例如:循環獲取容器中的元素。
可迭代對象(iterable)
for循環原理:
【1】獲取迭代器對象
【2】循環迭代(調用迭代器的__next__方法)
【3】捕獲StopIteration異常
list01=[1,2,3,4,5] # 可迭代對象:具有__iter__()方法,可以返回迭代器的對象
# for item in list01:
# print(item)
#1.獲取迭代器對象
iterator = list01.__iter__()
while True:
try:#如果獲取了全部元素,則執行except
# 2. 獲取下一個元素(迭代過程)
item = iterator.__next__()
print(item)
# 3. 停止迭代(異常StopIteration)
except StopIteration:
break # 跳出循環體
e.g. 不使用for循環,獲取字典所有元素
d01={"a":1,"b":2,"c":3}
iterator = d01.__iter__()
while True:
try:
key = iterator.__next__()
print(key,d01[key])
except:
break
- 定義:具有__iter__函數的對象,可以返回迭代器對象。
- 語法
- 創建:
class 可迭代對象類名:
def __iter__(self):
return 迭代器
- 使用:
for 變量名 in 可迭代對象:
語句
- 原理
迭代器 = 可迭代對象.__iter__()
while True:
try:
print(迭代器.__next__())
except StopIteration:
break
e.g.
class Skill:
pass
class SkillIterator:
"""
迭代器
"""
def __init__(self,target):
self.target = target
self.index = 0
def __next__(self):
# 返回下一個元素
# 如果索引越界,則拋出異常
if self.index > len(self.target)-1:
raise StopIteration()
# 返回下一個元素
item = self.target[self.index]
self.index += 1
return item
class SkillManager:
"""
可迭代對象
"""
def __init__(self,skills):
self.skills = skills
def __iter__(self):
# 創建迭代器對象 傳遞 需要迭代的數據
return SkillIterator(self.skills)
# 以下是客戶端代碼
manager = SkillManager([Skill(),Skill(),Skill()])
# 方式一
for item in manager:
print(item)
# 方式二
iterator = manager.__iter__()
while True:
try:
item = iterator.__next__()
print(item)
except:
break
迭代器對象(iterator)
- 定義:可以被next()函數調用並返回下一個值的對象。
- 語法:
class 迭代器類名:
def __init__(self, 聚合對象):
self.聚合對象 = 聚合對象
def __next__(self):
if 沒有元素:
raise StopIteration
return 聚合對象元素
- 說明:聚合對象通常是容器對象
- 作用:使用者只需要通過一種方式(next),便可簡單明瞭的獲取聚合對象中的各個元素,無需瞭解其內部結構。
生成器(generator)
- 定義:能夠動態(循環一次計算一次返回一次)提供數據的可迭代對象。
- 作用:在循環過程中,按照某種算法推算數據,不必創建容器存儲完整的結果,從而節省內存空間。數據量越大,優勢越明顯。
- 惰性(延遲)操作:通俗的講在需要的時候(for)才計算結果,而不是一次構建出所有結果。即循環(next)一次,計算一次,返回一次。(惰性查找:節省內存;立即查找:靈活獲取結果)
- 使用過的生成器對象,不會再被調用
生成器函數
- 定義:含有yield語句的函數,返回值爲生成器對象。
- 語法:
- 創建:
def 函數名():
…
yield 數據
…
- 調用:
for 變量名 in 函數名():
語句
e.g.生成器函數示例
def my_range(stop):
start = 0
while start < stop:
yield start
start += 1
for item in my_range(5):
print(item)
e.g. 在list01中,挑出所有的偶數
list01=[23,3,4,556,677,68,8,98,98]
def get_even01(target):
for item in target:
if item % 2 == 0:
yield item
def get_even02(target):
result=[]
for item in target:
if item % 2 == 0:
result.append(item)
return result
# 兩種方式結果一樣,大數據下推薦第一種方法(yield生成器)
iter01 = get_even01(list01)
for item in iter01:
print(item)
iter02 = get_even02(list01)
for item in iter02:
print(item)
- 說明:
- 調用生成器函數將返回一個生成器對象,不執行函數體。
- yield翻譯成“產生”或“生成”
- 執行過程
(1) 調用生成器函數,自動創建迭代器對象。
(2) 調用迭代器對象的__next__()方法才執行生成器函數體。
(3) 每次執行到yield關鍵字時返回數據,暫時離開。
(4) 待下次調用__next__()方法繼續執行。
內置生成器
枚舉函數enumerate
- 語法:
for 變量 in enumerate(可迭代對象):
語句
for 索引, 元素 in enumerate(可迭代對象):
語句
- 作用:遍歷可迭代對象時,可以將索引與元素組合爲一個元組。
list01=["a","b","c"]
for item in enumerate(list01):
# (索引,元素)
print(item) # (0,"a") (1,"b") (2,"c")
for index,element in enumerate(list01):
print(index,element) # 0 a 1 b 2 c
zip
- 語法:
for item in zip(可迭代對象1,可迭代對象2...):
語句
- 作用:將多個可迭代對象中對應的元素組合成一個元組,生成的元組個數由最小的可迭代對象決定。
list01 = [101,102,103]
list02 = ["A","B","C"]
for item in zip(list01,list02):
print(item) # (101,'A')
生成器表達式
- 定義:用推導式形式創建生成器對象
- 語法:變量 = ( 表達式 for 變量 in 可迭代對象 [if 真值表達式] )
list01 = [2,3,4,6]
# 列表推導式[]
result = [item**2 for item in list01]
print(result)
# 生成表達式
result = (item**2 for item in list01)
for item in result:
print(item)
e.g. 練習:使用列表推導式與生成器表達式,獲取list02中大於3的數據
list02 = [2,3,4,5]
res01 = [item for item in list02 if item>3] # 列表推導式:執行所有操作,保存所有結果
res02 = (item for item in list02 if item>3) # 生成器表達式:返回生成器對象
for item in res01: # 從結果中獲取數據
print(item)
for item in res02: # 循環一次,計算一次,返回一次
print(item)
函數式編程
- 定義:用一系列函數解決問題。
- 函數可以賦值給變量,賦值後變量綁定函數。
- 允許將函數作爲參數傳入另一個函數。
- 允許函數返回一個函數。
- 高階函數:將函數作爲參數或返回值的函數。
def fun01():
print("fun01執行")
# 將函數值賦值給變量a(沒有執行fun01)
a = fun01
# 調用變量a,間接執行函數fun01
a()
# --------------------------------
# 將方法fun01作爲方法的參數func進行傳遞
def fun02(func):
print("fun02執行")
# 對於fun02的定義者而言,不知道也不需要知道func的具體邏輯
func()
fun02(fun01)
函數作爲參數
將核心邏輯傳入方法體,使該方法的適用性更廣,體現了面向對象的開閉原則。
e.g.三個函數只有if條件不同的封裝方法
# 相同點
def find_demo(target,func):
for item in target:
# 本行代碼,使用 形參func將不變的與變化的隔離開
if func(item):
yield item
# 提取不同點
def condition01(item):
return item>5
def condition02(item):
return item % 2 != 0
def condition03(item):
return item<3
lambda表達式
- 定義:是一種匿名方法。
- 作用:作爲參數傳遞時語法簡潔,優雅,代碼可讀性強。隨時創建和銷燬,減少程序耦合度。
- 語法
- 定義:變量 = lambda 形參: 方法體
- 調用:變量(實參)
- 說明:
- 形參沒有可以不填
- 方法體只能有一條語句,且不支持賦值語句。
e.g. lambda表達式(匿名方法) 【語法:lambda 參數:方法體】
# 無參
a01 = lambda : print("我是lambda方法")
a01()
# 含參
a02 = lambda a: print("我是lambda方法,參數是",a)
a02(400)
# return 帶返回值
a03 = lambda : True # return True
a03()
e.g. lambda表達式的應用
解決步驟:
- 逐個解決問題
- 將共性提取到ListHelper中
- 將變化用lambda表示
class ListHelper:
@staticmethod
def find_all(target,func_condition):
for item in target:
if func_condition(item):
yield item
list01 = [1,2,33,4,45,6]
for item in ListHelper.find_all(list01,lambda item:item>5):
print(item)
內置高階函數
- map(函數,可迭代對象):使用可迭代對象中的每個元素調用函數,將返回值作爲新可迭代對象元素;返回值爲新可迭代對象。
list01=[
Enemy(101,"玄冥大佬",200,800,5),
Enemy(102,"玄冥小佬",150,700,3),
Enemy(103,"qtx",800,1000,50),
Enemy(104,"呂澤瑪利亞",0,300,2),
Enemy(105,"趙金多",500,900,10)
]
# 映射出所有敵人的名字
# e爲list01中的對象
for item in map(lambda e:e.name,list01):
print(item)
- filter(函數,可迭代對象):根據條件篩選可迭代對象中的元素,返回值爲新可迭代對象。
# 過濾出編號大於102的敵人
# e爲list01中的對象
for item in filter(lambda e:e.id>102,list01):
print(item.id)
- sorted(可迭代對象,key = 函數,reverse = bool值):排序,返回值爲排序結果。
# 按照血量升序排列
# e爲list01中的對象
# 不對list01產生任何變化,而是產生新的列表
for item in sorted(list01,key = lambda e:e.hp):
print(item.hp)
# 按照血量降序排列
for item in sorted(list01,key = lambda e:e.hp,reverse=True):
print(item.hp)
- max(可迭代對象,key = 函數):根據函數獲取可迭代對象的最大值。
# 獲取攻擊力最大的敵人
result = max(list01,key = lambda e:e.atk)
print(result.name)
- min(可迭代對象,key = 函數):根據函數獲取可迭代對象的最小值。
作用域LEGB
- 作用域:變量起作用的範圍。
- Local 局部作用域:函數內部。
- Encolsing 外部嵌套作用域:函數嵌套。
def fun01():
# fun01局部變量L
# E外部嵌套作用域
a = 1
def fun02():
b = 2 # fun02局部變量L
# print("fun02:",a) # 可以訪問外部嵌套變量a==1
# a = 2222222 # 沒有修改外部變量a,而是創建了新的局部變量a
# print("fun02:",a) # a==2222222
nonlocal a # 聲明外部嵌套變量a(內部改外面)
a = 2222
print("fun02:",a) # a == 2222
fun02()
print("fun01:",a) # a == 2222
fun01()
- Global 全局作用域:py文件內部
- Builtins內建模塊作用域:builtins.py
變量名查找規則
由內到外:L —> E —> G —> B
局部變量:
- 在方法體內部定義的變量
- 調用函數時才被創建,函數結束後自動銷燬。
全局變量:
- 定義在.py文件中的變量
- 函數體內部可以訪問,但是不能直接修改(先使用global語句聲明才能修改)。
函數作爲返回值
邏輯連續,當內部函數被調用時,不脫離當前的邏輯。
閉包
- 三要素:
- 必須有一個內嵌函數。
- 內嵌函數必須引用外部函數中變量。
- 外部函數返回值必須是內嵌函數。
- 語法
- 定義:
def 外部函數名(參數):
外部變量
def 內部函數名(參數):
使用外部變量
return 內部函數名
- 調用:
變量 = 外部函數名(參數)
變量(參數)
e.g. 閉包示例
def fun01():
print("fun01執行嘍")
a = 1
def fun02():
print("fun02執行嘍")
print("外部變量是:",a)
return fun02
# 得到的是內部函數
result = fun01()
# 調用內部函數,因爲內部函數使用了外部變量,所以稱之爲閉包
result() # 可以使用外部變量,說明外部函數在調用後沒有釋放
# 執行結果:
# fun01執行嘍
# fun02執行嘍
# 外部變量是:1
e.g. 壓歲錢案例
def give_gift_money(money):
"""
獲取壓歲錢
"""
print("得到了%d壓歲錢" %money)
def child_buy(target, price):
"""
孩子需要買的東西
"""
nonlocal money
if money > price:
money -= price
print("孩子花了%d錢,買了%s,剩下%s錢。" %(price,target,money))
else:
print("壓歲錢不夠了")
return child_buy
action = give_gift_money(10000)
action("98K",3500)
- 定義:在一個函數內部的函數,同時內部函數又引用了外部函數的變量。
- 本質:閉包是將內部函數和外部函數的執行環境綁定在一起的對象。
- 優點:內部函數可以使用外部變量。
- 缺點:外部變量一直存在於內存中,不會在調用結束後釋放,佔用內存。
- 作用:實現python裝飾器。
函數裝飾器decorators
- 定義:在不改變原函數的調用以及內部代碼情況下,爲其添加新功能的函數。
- 語法
def 函數裝飾器名稱(func):
def 內嵌函數(*args, **kwargs):
需要添加的新功能
return func(*args, **kwargs)
return 內嵌函數
@ 函數裝飾器名稱
def 原函數名稱(參數):
函數體
原函數(參數)
e.g. 裝飾器的使用
def print_func_name(func):
# 包裝新舊功能
def wrapper(*args, **kwargs): # 函數包裝後實際上執行的是wrapper函數
# 增加新功能
print(func.__name__)
# 舊功能
return func(*args, **kwargs)
return wrapper # 返回包裝器
@print_func_name # say_hello = print_func_name(say_hello)
def say_hello(name):
print(name,"hello")
return "haha"
@print_func_name
def say_goodbye(name,age):
print(name,age,"goodbye")
return "hehe"
print(say_hello("張無忌"))
print(say_goodbye("趙敏", 25))
e.g.打印執行時間
import time
def print_execute_time(func):
# 包裝新舊功能
def wrapper(*args, **kwargs):
# 記錄執行前的時間
start_time = time.time()
result = func(*args, **kwargs)
# 統計執行時間
execute_time = time.time() - start_time
print("執行時間是:",execute_time)
return result
return wrapper # 返回包裝器
-
本質:
使用 @ 函數裝飾器名稱 修飾原函數,等同於:
原函數名稱 = 函數裝飾器名稱(原函數名稱)
創建與原函數名稱相同的變量,關聯內嵌函數;故調用原函數時執行內嵌函數。 -
裝飾器鏈:一個函數可以被多個裝飾器修飾,執行順序爲從近到遠。