模块 Module
定义
包含一系列数据、函数、类的文件,通常以.py结尾。
作用
让一些相关的数据,函数,类有逻辑的组织在一起,使逻辑结构更清晰
导入
Import
- 语法:
import 模块名
import 模块名 as 别名
- 作用:将某模块整体导入到当前模块中
- 使用:
模块名.成员
from import
- 语法:
from 模块 import 成员们 [as 别名1]
- 作用:将模块内的一个或多个成员导入到当前模块的作用域中。
from import *
- 语法:
from 模块名 import *
- 作用:将某模块的所有成员导入到当前模块。
- 模块中一下划线(_)开头的属性,不会比导入,通常称这些成员为隐藏成员。
模块变量
__all__
变量:定义可导出成员,仅对from xx import *
语句有效。__doc__
变量:文档字符串__file__
变量:模块对应的文件路径名__name__
变量:模块自身名字,可以判断是否为主模块- 当此模块作为主模块(第一个运行的模块)运行时,
__name__
绑定“__main__”
,不是主模块,而是被其他模块导入时,存储模块名
- 当此模块作为主模块(第一个运行的模块)运行时,
加载过程
在模块导入时,模块的所有语句会执行。如果一个模块已经导入,则再次导入时不会重新执行模块内的语句
分类
- 内置模块(builtins),在解析器的内部可以直接使用。
- 标准库,安装python时已安装且可直接使用。
- 第三方模块(通常为开源),需要自己安装。
- 用户自己编写的模块(可以作为其他人的第三方模块)
搜索顺序
搜索内建模块(builtins)
sys.path提供的路径,通常第一个是程序运行时的路径。
包 Package
定义
将模块以文件夹的形式进行分组管理。
作用
让一些相关的模块组织在一起,是逻辑结构更加清晰。
导入
from 包名 import 模块名 [as 模块新名]
from 包名.子包名 import 模块名 [as 模块新名]
from 包名.子包名.模块名 import 成员名 [as 属性新名]
from 包名 import *
from 包名.模块名 import *
搜索顺序
sys.path
提供的路径
__init__.py
文件是包内必须存在的文件
会在包加载时被自动调用
异常处理 Error
异常
- 定义:运行时检测到的错误。
- 现象:当异常发生时,程序不会在向下执行,而转到函数的调用语句
- 常见异常类型:
- 名称异常(NameError):变量未定义。
- 类型异常(TypeError):不同类型数据进行运算。
- 索引异常(IndexError):超出索引范围。
- 属性异常(AttributeError):对象没有对应名称的属性。
- 键异常(KeyError):没有对应名称的键。
- 实现异常(NotImplementedError):尚未实现的方法。
- 异常基类Exception。
处理
1.语法:
try: # 可能出发异常的语句 except 错误类型 1 [as 变量 1] 处理语句1 except 错误类型 2 [as 变量 2] 处理语句2 except Exception [as 变量 3]: 不是以上错误类型的语句 else: 未发生异常执行的语句 finally: 无论是否发生异常的语句
2.作用:将程序由异常状态转为正常流程。
3.说明:
- as自居适用于绑定错误对象的变量,可以省略。
- except字句可以有一个或多个,用来捕获某种类型的错误。
- else字句最多只能有一个。
- finally字句最多只能有一个,如果没有except字句,必须存在。
- 如果异常没有被捕获到,会向上层(调用处)继续传递,直到程序终止运行
rasie语句
- 作用:跑出一个错误,让程序进入异常状态。
- 目的:在程序调用层数较深时,向主调函数传递错误信息要层层return比较麻烦,所以人为抛出异常,可以直接传递错误信息
自定义异常
1.定义
class 类名 Error(Exception): def __init__(self,参数): super().__init__(参数) self.数据 = 参数
2.调用:
try: ... rasie 自定义异常类名(参数) ... except 定义异常类 as 变量名: 变量名.数据
3.作用:封装错误信息
4.代码示例:
""" 自定义异常 练习:成绩异常(1-100) """ class AgeError(Exception): """ 封装错误信息 """ def __init__(self, msg, code, age_value): super().__init__(msg) self.msg = msg self.code = code self.age_value = age_value class Wife: def __init__(self, age): self.age = age @property def age(self): return self.__age @age.setter def age(self, value): if 20 <= value <= 30: self.__age = value else: # print("我不要") # raise ValueError("我不要") # 人为抛出异常 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
1.定义:具有__iter__函数的对象,可以返回迭代器对象。
2.语法:
创建:
class 可迭代对象名称: def __iter__(self): return 迭代器
使用:
for 变量名 in 可迭代对象: 语句
3.原理
迭代器 = 可迭代对象.__iter__() while True: try: print(迭代器.__next__()) except StopIteration: break
4.代码示例
""" 可迭代对象:具有__iter()__方法,可以返回迭代器对象的对象。 """ list01 = [1, 2, 4, 5] # for i in list01: # print(i) # 面试题 # 能够被for循环的条件是:可迭代对象(具有__iter()__方法的对象) # for循环原理 # 1. 获取迭代器对象。 # 2. 循环迭代(调用迭代器的__next()__方法) # 3. 捕获StopIteration异常 # 1. iterator = list01.__iter__() # 2. # item = iterator.__next__() # print(item) # item = iterator.__next__() # print(item) # item = iterator.__next__() # print(item) # item = iterator.__next__() # print(item) # 3. # item = iterator.__next__() # print(item) # 错误 :StopIteration --> 停止迭代 # 1.获取迭代器对象。 iterator = list01.__iter__() while True: try: # 如果获取了全部元素,则执行except # 2. 获取下一个元素(迭代过程) iterator.__next__() # 3. 停止迭代(StopIteration) except StopIteration: break # 退出循环体
迭代器对象iterator
1.定义:可以被next()函数调用并返回下一个值的对象。
2.语法
class 迭代器类名: def __init__(self,聚合对象): self.聚合对象 = 聚合对象 def __next__(self): if 没有元素: raise StopIteration return 聚合对象元素
3.说明:聚合对象通常是容器对象
4.作用:使用者只需通过一种方式,便可简洁明了的获取聚合对象中各个元素,而又无需了解其内部结构。
5.代码示例
""" 迭代器 """ class Skill: pass class SkillIterator: def __init__(self, target): self.target = target self.index = 0 def __next__(self): # 如果越界则抛出异常 if self.index >= len(self.target): 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.skills: # # for item in manager: # TypeError: 'SkillManager' object is not iterable # print(item) # iterator = manager.__iter__() # while True: # try: # item = iterator.__next__() # print(item) # except StopIteration: # break for i in manager: print(i)
6. 一个更深次的练习
""" 迭代器 --> yield 练习:exercise04/exercise05 """ 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) def __iter__(self): """ 执行过程: 1.调用__iter__()方法不执行 2.调用__next__()方法时执行,到yield语句暂时离开. 3.再次调用__next__()方法时,从上次离开的代码开始执行,到yield语句暂时离开 4. 待执行完方法体,抛出StopIteration异常. 原理:如果方法体中包含yield关键字,那么会自动生成迭代器对象. 生成迭代器代码的大致规则: 1. 将yield关键字以前的代码,放到__next__方法中. 2. 将yield关键字以后的数据,作为__next__方法的返回值 """ # print("准备返回第一个元素") # yield self.skills[0] # 暂时离开点 再次执行点 # # print("准备返回第二个元素") # yield self.skills[1] # # print("准备返回第三个元素") # yield self.skills[2] for item in self.skills: yield item #---------------以下是客户端代码--------------------- manager = SkillManager([Skill(), Skill(), Skill()]) # for item in manager: # print(item) iterator = manager.__iter__() while True: try: item = iterator.__next__() print(item) except Exception as e: print(e) break
生成器generator
- 定义:能够动态(循环一次计算一次返回一次)提供数据的可迭代对象。
- 作用:在循环过程中,按照某种算法推算数据,不必创建容器存储结果,从而节省内存空间。数据量越大,优势越明显。
- 以上作用也称之为延迟操作或者惰性操作,通俗的讲就是在需要的时候才计算结果,而不是一次构建出所有结果。
生成器函数
1.定义:含有yield语句的函数,返回值为生成器对象。
2.语法
-- 创建: def 函数名(): … yield 数据 … -- 调用: for 变量名 in 函数名(): 语句
3.说明
- 调用生成器函数将返回一个生成器对象,不执行函数体。
- yield翻译为”产生”或”生成”
4.执行过程
- 调用生成器函数会自动创建迭代器对象。
- 调用迭代器对象的__next__()方法时才执行生成器函数。
- 每次执行到yield语句时返回数据,暂时离开。
- 待下次调用__next__()方法时继续从离开处继续执行。
5.原理:生成迭代器对象的大致规则如下
- 将yield关键字以前的代码放在next方法中
- 将yield关键字后面的数据作为next方法的返回值。
6.特点:惰性操作/延迟操作(循环一次,计算一次,返回一次.)
7.本质: 迭代器 + 可迭代对象
内置生成器
枚举函数enumerate
- 语法:
for 变量 in enumerate(可迭代对象): 语句 for 索引, 元素in enumerate(可迭代对象): 语句
- 作用:遍历可迭代对象时,可以将索引与元素组合为一个元组。
zip
- 语法:
for item in zip(可迭代对象1, 可迭代对象2….): 语句
- 作用:将多个可迭代对象中对应的元素组合成一个个元组,生成的元组个数由最小的可迭代对象决定。
生成器表达式
- 定义:用推导式形式创建生成器对象。
- 语法:变量 = ( 表达式 for 变量 in 可迭代对象 [if 真值表达式] )
函数式编程
- 定义:用一系列函数解决问题。
- 函数可以赋值给变量,赋值后变量绑定函数。
- 允许将函数作为参数传入另一个函数。
- 允许函数返回一个函数。
- 高阶函数:将函数作为参数或返回值的函数。
函数作为参数
将核心逻辑传入方法体,使该方法的适用性更广,体现了面向对象的开闭原则
一个简单的函数作为参数的示例
lambda 表达式
- 定义: 是一种匿名方法
- 作用:作为参数传递时语法简洁,优雅,代码可读性强。随时创建和销毁,减少程序耦合度。
- 说明:
- 形参没有可以不填
- 方法体只能有一条语句,且不支持赋值语句。
- 语法:
-- 定义: 变量 = lambda 形参: 方法体 -- 调用: 变量(实参)
lambda表达式的实际应用
内置高阶函数
- map(函数,可迭代对象):使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。
- filter(函数,可迭代对象):根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。
- sorted(可迭代对象,key = 函数,reverse = bool值):排序,返回值为排序结果。
- max(可迭代对象,key = 函数):根据函数获取可迭代对象的最大值。
- min(可迭代对象,key = 函数):根据函数获取可迭代对象的最小值。
函数作为返回值
闭包
- 三要素
- 必须有一个内嵌函数。
- 内嵌函数必须引用外部函数中变量。
- 外部函数返回值必须是内嵌函数。
- 定义:在一个函数内部的函数,同时内部函数又引用了外部函数的变量。
- 本质:闭包是将内部函数和外部函数的执行环境绑定在一起的对象。
- 优点:内部函数可以使用外部变量。
- 缺点:外部变量一直存在于内存中,不会在调用结束后释放,占用内存。
- 作用:实现python装饰器。
- 语法:
def fun01(): print("fun01执行喽") a = 1 def fun02(): print("fun02执行喽") print("外部变量是:", a) return fun02 # 得到的是内部函数 result = fun01() # 调用内部函数,因为内部函数使用了外部变量,所以称之为闭包. result() # 可以使用外部变量,说明外部函数在调用后没有释放.
# 案例: def give_gift_money(money): """ 获取压岁钱 """ print("得到了%d压岁钱" % money) def child_buy(target, price): """ 孩子需要买东西 """ nonlocal money if money >= price: money -= price print("孩子花了%d钱,买了%s,还剩下%d钱." % (price, target, money)) else: print("压岁钱不够了") return child_buy action = give_gift_money(10000) action("98k", 3500) action("小猪佩奇", 300) action("大黄蜂", 8000) # 体会:闭包使得逻辑连续(因为内部函数可以使用外部变量).
函数装饰器decorators
定义:在不改变原函数的调用以及内部代码情况下,为其添加新功能的函数。
本质:使用“@函数装饰器名称
”修饰原函数,等同于创建与原函数名称相同的变量,关联内嵌函数;故调用原函数时执行内嵌函数。
原函数名称 = 函数装饰器名称(原函数名称)
装饰器链:
一个函数可以被多个装饰器修饰,执行顺序为从近到远。
语法
装饰器的调用过程