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. 装饰器链:一个函数可以被多个装饰器修饰,执行顺序为从近到远。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值