Python模塊包異常處理

模塊(Module)

定義

包含一系列數據、函數、類的文件,通常以.py結尾

作用

讓一些相關的代碼,有邏輯的組織在一起,使結構更加清晰。

導入

【1】import

  1. 語法:import 模塊名 [as 別名]
  2. 作用:將某個模塊整體導入到當前模塊
  3. 本質:使用變量名(模塊名)關聯指定模塊代碼。
  4. 使用:模塊名.成員
  • 導入方式:
    導入模塊名稱
    本質:將該模塊作用域賦值給變量module01
import module01

module01.fun01()#調用module01中的函數
c01 = module01.MyClass01()#調用module01中的類
c01.fun02()#調用類中的方法

【2】from import

  1. 語法:from 模塊名 import 成員 [as 別名]
  2. 作用:將模塊內的一個或多個成員導入到當前模塊的作用域中。
  3. 使用:成員
  • 導入方式:
    本質:將該模塊指定成員賦值給變量fun01,MyClass01
from module01 import fun01,MyClass01

fun01()
c01 = MyClass01()
c01.fun02()

【3】from import *

  1. 語法:from 模塊名 import *
  2. 作用:將某模塊的所有成員導入到當前模塊
  3. 模塊中以單下劃線(_)開頭的屬性,不會被導入,通常稱這些成員爲隱藏成員
  • 導入方式:
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__": # 如果程序從當前模塊運行,則執行下列的測試代碼;如果當前模塊被主模塊導入,則下列測試代碼不再執行

加載過程

在模塊導入時,模塊的所有語句都會執行。
如果一個模塊已經導入,則再次導入時不再重複執行語句。

分類

  1. 內置模塊(builtins):在解釋器的內部可以直接使用。
  2. 標準庫模塊:安裝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"))
  1. 第三方模塊(通常開源):需要自行下載安裝,再導入使用。
  2. 自定義模塊:用戶自己編寫的模塊,經過導入後可直接使用。

搜索順序

搜索內建模塊(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)

異常

  1. 定義:運行時檢測到的錯誤。
  2. 現象:當異常發生時,程序不再向下繼續執行,而轉到函數的調用語句。
  3. 常見異常類型:
  • 名稱異常(NameError):變量未定義
  • 數值異常(ValueError):值錯誤
  • 類型異常(TypeError):不同類型數據進行運算
  • 索引異常(IndexError):超出索引範圍
  • 屬性異常(AttributeError):對象沒有對應名稱的屬性
  • 鍵異常(KeyError):沒有對應名稱的鍵
  • 未實現異常(NotImplementedError):尚未實現的方法
  • 異常基類Exception

處理

  1. 語法:
try:
	可能觸發異常的語句
except 錯誤類型1 [as 變量1]:
	處理語句1
except 錯誤類型2 [as 變量2]:
	處理語句2
except Exception [as 變量3]:
	不是以上錯誤類型的處理語句
else:
	未發生異常的語句
finally:
	無論是否異常,一定執行的代碼
  1. 作用:將程序由異常狀態轉換爲正常流程
  2. 說明:
  • as子句是用於綁定錯誤對象的變量,可以省略
  • except子句可以有一個或者多個,用來捕獲某種類型的錯誤
  • else子句最多隻能有一個
  • finally子句最多隻能有一個,如果沒有except子句,必須存在。
  • 如果異常沒有被捕獲到,會向上層(調用處)繼續傳遞,直到程序終止運行。

raise語句

  1. 作用:拋出一個錯誤,讓程序進入異常狀態。
  2. 目的:在程序調用層數較深時,向主程序傳遞錯誤信息要層層return比較麻煩,所以建議人爲拋出異常,可以直接傳遞錯誤信息。

自定義異常

  1. 定義
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 
  1. 調用
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)
  1. 作用:封裝錯誤信息

迭代(瞭解)

每一次對過程的重複稱之爲一次”迭代”,而每一次迭代得到的結果會作爲下一次迭代的初始值。例如:循環獲取容器中的元素。

可迭代對象(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 
  1. 定義:具有__iter__函數的對象,可以返回迭代器對象。
  2. 語法
  • 創建:
class 可迭代對象類名:
	def __iter__(self):
		return 迭代器
  • 使用:
for 變量名 in 可迭代對象:
	語句
  1. 原理
迭代器 = 可迭代對象.__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)

  1. 定義:可以被next()函數調用並返回下一個值的對象。
  2. 語法:
class 迭代器類名:
	def __init__(self, 聚合對象):
		self.聚合對象 = 聚合對象

	def __next__(self):
		if 沒有元素:
			raise StopIteration
		return 聚合對象元素
  1. 說明:聚合對象通常是容器對象
  2. 作用:使用者只需要通過一種方式(next),便可簡單明瞭的獲取聚合對象中的各個元素,無需瞭解其內部結構。

生成器(generator)

  1. 定義:能夠動態(循環一次計算一次返回一次)提供數據的可迭代對象。
  2. 作用:在循環過程中,按照某種算法推算數據,不必創建容器存儲完整的結果,從而節省內存空間。數據量越大,優勢越明顯。
  3. 惰性(延遲)操作:通俗的講在需要的時候(for)才計算結果,而不是一次構建出所有結果。即循環(next)一次,計算一次,返回一次。(惰性查找:節省內存;立即查找:靈活獲取結果)
  4. 使用過的生成器對象,不會再被調用

生成器函數

  1. 定義:含有yield語句的函數,返回值爲生成器對象。
  2. 語法:
  • 創建:
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) 
  1. 說明:
  • 調用生成器函數將返回一個生成器對象,不執行函數體。
  • yield翻譯成“產生”或“生成”
  1. 執行過程
    (1) 調用生成器函數,自動創建迭代器對象。
    (2) 調用迭代器對象的__next__()方法才執行生成器函數體。
    (3) 每次執行到yield關鍵字時返回數據,暫時離開。
    (4) 待下次調用__next__()方法繼續執行。

內置生成器

枚舉函數enumerate

  1. 語法:
for 變量 in enumerate(可迭代對象):
	語句

for 索引, 元素 in enumerate(可迭代對象):
	語句
  1. 作用:遍歷可迭代對象時,可以將索引與元素組合爲一個元組。
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

  1. 語法:
for item in zip(可迭代對象1,可迭代對象2...):
	語句
  1. 作用:將多個可迭代對象中對應的元素組合成一個元組,生成的元組個數由最小的可迭代對象決定。
list01 = [101,102,103]
list02 = ["A","B","C"]
for item in zip(list01,list02):
	print(item) # (101,'A')

生成器表達式

  1. 定義:用推導式形式創建生成器對象
  2. 語法:變量 = ( 表達式 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)

函數式編程

  1. 定義:用一系列函數解決問題。
  • 函數可以賦值給變量,賦值後變量綁定函數。
  • 允許將函數作爲參數傳入另一個函數。
  • 允許函數返回一個函數。
  1. 高階函數:將函數作爲參數或返回值的函數。
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表達式

  1. 定義:是一種匿名方法。
  2. 作用:作爲參數傳遞時語法簡潔,優雅,代碼可讀性強。隨時創建和銷燬,減少程序耦合度。
  3. 語法
  • 定義:變量 = lambda 形參: 方法體
  • 調用:變量(實參)
  1. 說明:
  • 形參沒有可以不填
  • 方法體只能有一條語句,且不支持賦值語句。

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表達式的應用

解決步驟:

  1. 逐個解決問題
  2. 將共性提取到ListHelper中
  3. 將變化用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)

內置高階函數

  1. 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)
  1. filter(函數,可迭代對象):根據條件篩選可迭代對象中的元素,返回值爲新可迭代對象。
# 過濾出編號大於102的敵人
# e爲list01中的對象
for item in filter(lambda e:e.id>102,list01):
	print(item.id)
  1. 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)
  1. max(可迭代對象,key = 函數):根據函數獲取可迭代對象的最大值。
# 獲取攻擊力最大的敵人
result = max(list01,key = lambda e:e.atk)
print(result.name)
  1. min(可迭代對象,key = 函數):根據函數獲取可迭代對象的最小值。

作用域LEGB

  1. 作用域:變量起作用的範圍。
  2. Local 局部作用域:函數內部。
  3. 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()
  1. Global 全局作用域:py文件內部
  2. Builtins內建模塊作用域:builtins.py

變量名查找規則

由內到外:L —> E —> G —> B

局部變量:

  • 在方法體內部定義的變量
  • 調用函數時才被創建,函數結束後自動銷燬。

全局變量:

  • 定義在.py文件中的變量
  • 函數體內部可以訪問,但是不能直接修改(先使用global語句聲明才能修改)。

函數作爲返回值

邏輯連續,當內部函數被調用時,不脫離當前的邏輯。

閉包

  1. 三要素:
  • 必須有一個內嵌函數。
  • 內嵌函數必須引用外部函數中變量。
  • 外部函數返回值必須是內嵌函數。
  1. 語法
  • 定義:
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))
		elseprint("壓歲錢不夠了")
	return child_buy

action = give_gift_money(10000)
action("98K"3500)
  1. 定義:在一個函數內部的函數,同時內部函數又引用了外部函數的變量。
  2. 本質:閉包是將內部函數和外部函數的執行環境綁定在一起的對象。
  3. 優點:內部函數可以使用外部變量。
  4. 缺點:外部變量一直存在於內存中,不會在調用結束後釋放,佔用內存。
  5. 作用:實現python裝飾器。

函數裝飾器decorators

  1. 定義:在不改變原函數的調用以及內部代碼情況下,爲其添加新功能的函數。
  2. 語法
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 # 返回包裝器
  1. 本質:
    使用 @ 函數裝飾器名稱 修飾原函數,等同於:
    原函數名稱 = 函數裝飾器名稱(原函數名稱)
    創建與原函數名稱相同的變量,關聯內嵌函數;故調用原函數時執行內嵌函數。

  2. 裝飾器鏈:一個函數可以被多個裝飾器修飾,執行順序爲從近到遠。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章