九、Python高级特性
1、迭代器
1.1 认识迭代器
- 迭代器
- 迭代类似于循环,提供了迭代方法的容器称为迭代器
- 可迭代对象
- 在定义对象时,有__ iter __( )方法的就是可迭代对象
- 迭代器的核心方法
- iter( ) 和 next( )方法
- iter( ) 方法用于创建迭代对象
- next( ) 方法用于遍历对象的元素
# 迭代器示例
list1 = [1, 2, 3, 4]
print('list1的对象类型:', type(list1))
l = iter(list1)
print('iter(list1)的对象类型:', type(l))
print(next(l))
print(next(l))
print(next(l))
print(next(l))
1.2 自定义迭代器
-
迭代器类
- 在类中定义了__ iter __ ( )和__ next __ ( )方法的类
-
可迭代类
- 类中的__ iter __( )方法里面使用了自定义的迭代器类实现迭代过程
1.3 迭代器的作用与扩展
-
使用迭代器的优点
- 直接循环时将所有数据加载如内存,对内存消耗大
- 迭代器每次迭代智慧取出当前迭代的数据存储在内存进行读取,上一次迭代的数据会在内存中销毁,并且其他数据不会加载到内存中
- 在对象存储数据量过大的情况下,迭代器可以节省大量内存开销,提高程序的运行速度
-
迭代器工具
- itertools模块提供了丰富的迭代器工具
- itertools模块提供了近20个迭代器函数,主要分为:
- 无限迭代器:永无止尽的输出迭代对象的元素,当对象元素有限是就重复输出
- 迭代短序列:通过判断条件进行输出元素
- 组合迭代序列:将多个迭代对象的元素按照一定规则进行合并或排序等操作
2、 生成器
2.1 生成器定义
-
生成器
- 在Python中,使用了关键字yield的函数被称为生成器
- 生成器将返回一个迭代器的函数,并且生成器只能用于迭代操作;
-
协同程序
- 函数可以暂停或挂起,并在需要的时候从程序离开的地方继续或者重新开始
-
生成器运行过程
- 调用生成器运行的过程中,每次执行到关键字yield的时候,函数就会暂停运行,并将关键字yield后面设置的值作为返回值。当下一次执行next( )方法的时候,程序会从当前位置继续运行
# 生成器
def myGen():
location = 1
print('location is:', location)
yield location
location += 1
print('location is:', location)
yield location
location += 1
print('location is:', location)
yield location
2.2 生成器推导式
- 生成器推导式
- 生成器推导式是使用小括号表示的,小括号里面的代码与列表推导式的代码相同,以for循环为主,在每次循环中可以使用if语句进行判断
# 创建生成器g
g = (i for i in range(10) if i % 2 == 0)
# 遍历输出生成器g的每个元素
for i in g:
print(i)
3、装饰器
3.1 装饰器的定义
- 装饰器
- 装饰器是为已有的函数方法或类添加新的功能,无须重新定义
- 装饰器的表示语法是在函数或类的前面添加【 @ 】符号
@decorator
def myDef():
pass
- 装饰器的类型
- 装饰器可以使用函数方法定义,称为函数装饰器
- 装饰器可以使用类方式定义,称为类装饰器
- 装饰器可以根据需要设置参数,分为有参装饰器和无参装饰器
3.2 无参数的函数装饰器
- 闭包
- 闭包被称为词法闭包或函数闭包;它是引用了自由变量的函数
- 如果在一个函数内部嵌套了另外一个函数,并且这个内部函数对外部作用域的变量进行了引用,那么这个内部函数称为闭包;根据理解装饰器是一个函数,并且函数里面还定义了一个函数
- 装饰器的定义过程说明:
- 装饰器是以函数方式表达,并且在函数里面又定义了一个函数
- 最外层函数设置了参数fun,而内层函数可以调用最外层的函数的参数fun
- 参数fun表示被装饰的函数名称,所以内层函数可以调用被装饰的函数
- 最外层函数必须使用return设置返回值(返回值为内层函数名称)
# myDef函数无参数,无返回值
def set_fun(fun):
def call_fun():
print('这是闭包函数')
print(f'参数fun的值为:{fun}')
fun()
return call_fun
# 被装饰函数myDef()
@set_fun
def myDef():
print('---runing---')
if __name__ == '__main__':
myDef()
# myDef函数有参数,无返回值
def set_fun(fun):
def call_fun(num, *args, **kwargs):
print('这是闭包函数')
print(f'参数fun的值为:{fun}')
print(f'参数num的值为:{num}')
fun(num, *args, **kwargs)
return call_fun
# 被装饰函数myDef()
@set_fun
def myDef(num, *args, **kwargs):
print('---runing---')
if __name__ == '__main__':
myDef(1)
# myDef函数有参数,有返回值
def set_func(fun):
def call_func(num, *args, **kwargs):
print('这是闭包函数')
print(f'参数fun的值为:{fun}')
print(f'参数num的值为:{num}')
# 如果被装饰函数设有返回值,那么装饰器的内层函数也要设置相应的返回值
# 返回值必须为被装饰函数fun()的调用过程
return fun(num, *args, **kwargs)
return call_func
@set_func
def myDef(num, *args, **kwargs):
print('---------running---------')
return num
if __name__ == '__main__':
m = myDef(10)
print('函数返回值为:', m)
# 一个函数使用两个或两个以上装饰器,无论函数是否有返回值,装饰器的内层函数必须设置返回值
def set_func1(fun):
def call_func1(num, *args, **kwargs):
print('这是第一个闭包函数')
print(f'参数fun的值为:{fun}')
print(f'参数num的值为:{num}')
return fun(num, *args, **kwargs)
return call_func1
def set_func2(fun):
def call_func2(num, *args, **kwargs):
print('这是第二个闭包函数')
print(f'参数fun的值为:{fun}')
print(f'参数num的值为:{num}')
return fun(num, *args, **kwargs)
return call_func2
@set_func1
@set_func2
def myDef(num, *args, **kwargs):
print('---------running---------')
return num
if __name__ == '__main__':
m = myDef(10)
print('函数返回值为:', m)
- 总结
- 装饰器的外层函数的名称代表装饰器的名称,外层函数的参数fun代表被装饰函数的名称(函数myDef()),并且外层函数必须使用return设置返回值,返回值为内层函数的名称。
- 装饰器的内层函数主要调用被装饰函数,内层函数的参数等同于被装饰函数的参数。
- 如果被装饰函数设有返回值,内层函数也要设置相应的返回值,返回值必须为被装饰函数fun()(myDef())的调用过程。
- 多个装饰器装饰同一个函数,必须为装饰器的内层函数设置返回值;装饰器的执行顺序与被装饰函数的装饰器设置相关,从上往下执行,
3.3 带参数的函数装饰器
- 如果要在装饰器中设置参数,整个装饰器就要定义3层函数
def set_para(parameter, *args, **kwargs):
print('---第一层函数---')
print(f'装饰器的参数parameter的值为:{parameter}')
print(f'装饰器的参数args的值为:{args}')
def set_func(fun):
print('---第二层函数---')
def call_func(num, *args, **kwargs):
print('---第三层函数---')
print(f'参数fun的值为:{fun}')
print(f'参数num的值为:{num}')
return fun(num, *args, **kwargs)
return call_func
return set_func
@set_para('Hello', 'Python')
def myDef(num, *args, **kwargs):
print('---------running---------')
return num
if __name__ == '__main__':
m = myDef(10)
print('函数返回值为:', m)
- 如果装饰器需要设置函数参数,整个装饰器就需要设置3层函数,每层函数的功能说明如下:
- 第一层函数负责接收装饰器的参数,装饰器的参数设置方式与普通函数的参数设置相同,并且它必须使用return设置返回值,返回值为第二层函数的名称。
- 第二层函数接收被装饰函数,其函数参数fun代表被装饰函数的名称,它能使用第一层的函数参数,并且必须使用return设置返回值,返回值为第三层函数的名称。
- 第三层函数负责调用被装饰函数,并且能使用第一层和第二层的函数参数,函数自身的参数等同于被装饰函数的参数,其返回值必须为被装饰函数的调用过程。
3.4 使用类定义装饰器
- 使用类方式实现装饰器功能只需要定义初始化方法__ init __ ( ) 和内置方法 __ call __ ( )
# 类装饰器没有参数
class decorator:
def __init__(self, fun):
self.fun = fun
def __call__(self, num, *args, **kwargs):
res = self.fun(num, *args, **kwargs)
return res
@decorator
def myDef(num, *args, **kwargs):
print('---------Running---------')
return num
if __name__ == '__main__':
m = myDef(10)
print('函数返回值为:', m)
- 对比类装饰器与函数装饰器发现:
- 初始化方法__ init __( )等同于无参数函数装饰器的最外层函数,都是负责接收被装饰函数
- 内置方法__ call __( )等同于无参数函数装饰器的内层函数,主要实现被装饰函数的调用过程
# 类装饰器设置参数
class decorator:
def __init__(self, para):
self.para = para
def __call__(self, func):
print(f'装饰器的参数为:{self.para}')
def wrapper(num, *args, **kwargs):
res = func(num, *args, **kwargs)
return res
return wrapper
@decorator('hello')
def myDef(num, *args, **kwargs):
print('---------Running---------')
return num
if __name__ == '__main__':
m = myDef(10)
print('函数返回值为:', m)
- 带参数的类装饰器定义过程如下:
- 初始化方法__ init __( )负责接收装饰器的参数,等同于带参数函数装饰器的第一层函数。
- 内置方法__ call __( )负责接收被装饰函数,其参数fun代表被装饰函数的名称,等同于带参数函数装饰器的第二层函数
- 内置方法__ call __( )里面的函数方法wrapper( )负责调用被装饰函数,等同于带参数函数装饰器的第三层函数。
3.5 装饰器在类中的应用
- 在函数或类的起那么添加【 @ 】符号和装饰器名称即可使用已定义的装饰器
# 在函数中使用装饰器
@decorator
def myDef():
pass
# 在类中使用装饰器
@decorator
class myDef():
pass
- 除了在函数或类的前面使用装饰器外,还可以在类里面的某个方法或属性中使用装饰器
十、异常处理机制
1、异常的类型
-
异常是指程序在运行过程中出现问题而导致无法执行,如程序的逻辑或算法错误、计算机资源不足或IO错误等
-
Python中的异常是由类定义的,所有的异常都是来自于BaseException类,不同类型的异常都继承自父类BaseException
-
Python中提供了异常处理机制,并定义了不同类型的异常信息:如AssertionError、AttributeError
2、捕捉异常
- 在Python中,处理异常的语法由4个关键字组成,即try、except、else和finally
- 具体语法格式如下:
try:
# 程序运行的代码
except NameError as err:
# 只捕捉NameError的错误类型
print('错误信息1', err)
except Exception as err:
print('错误信息2', err)
except:
print('错误信息3')
else:
print('如果没有异常就执行此处代码')
finally:
print('不管是否有异常都会执行此处代码')
3、自定义异常
- 自定义异常抛出除了监测错误之外,还可以用于代码的布局设计和程序的逻辑控制,通过抛出异常可以执行不同的代码块
- 自定义异常抛出由关键字raise实现,关键字后面填写异常的类型及异常信息
if __name__ == '__main__':
try:
raise NameError('自定义异常抛出')
except Exception as err:
print('这是Exception错误,错误信息是:', err)
- 自定义一个异常类只需要继承Exception类即可
# 自定义异常类型
class MyError(Exception):
pass
if __name__ == '__main__':
try:
# 抛出自定义异常
raise MyError('自定义异常抛出')
# 捕捉自定义异常类
except MyError as err:
print('这是MyError错误,错误信息', err)
4、异常的追踪术
- Python的标准库提供了traceback模块,它能准确定位代码的异常信息
import traceback
class A:
pass
try:
a = A()
print(a.name)
a.name = 10
print(a.name)
except Exception as e:
traceback.print_exc()
十一、模块与包
1、模块的导入与使用
- 模块是由一组类、函数或变量等元素组成的,它存储在文件中,模块文件的扩展名可能是【.py】或【.pyc】
- Python使用关键字import用于实现模块导入功能
# 导入方式1
import os,traceback,re
# 导入方式2
import os
import traceback
import re
2、包的导入与使用
-
包是在同一组相同文件夹中放置了许多模块文件,这个文件就叫包,也称类库
-
包的导入方式:
# 导入包
import html
# 导入包中的模块或子包
import html.parser
# 导入包中多层子包
import A.B.C.D
3、导入方式from…import…
- 使用关键字from…import…导入模块或包
# 示例
from email import message
from email.mime import image
# 同一个包中导入多个模块文件
from email import meassage,parser,feedparser
from email.mime import image,base,multipart
# 导入模块文件中某个类、函数方法或变量
from email.message import EmailMessage
# 导入所有模块文件或者模块中所有的类、函数方法或变量
from email import *
from email.message import *
4、重命名模块与包
- Python可以对导入的模块和包进行重新命名,使用关键字as即可实现
# 示例
from email import message as msg
from email.mime import image as img
- 关键字as 还适用于单一导入方式import
import email.message as msg
import email.mime.image as img
- 关键字as不支持导入方式是全部模块文件、类、函数方法或变量的重命名
5、自定义模块和包
- 模块或包的自定义没有规定语法格式,只要定义的模块或包中含有类、函数方法或属性即可
6、重新加载模块与包
- 一般情况下,我们导入模块或包后,当模块或包代码发生变化的时候,程序不会因为模块或包变化而变化
- 在不中断程序的情况下,当导入模块或包的代码发生变化后,Python提供了importlib模块的reload( )方法重新加载模块或包
7、动态添加模块与包
- 使用内置函数 __ import __ ( )可以动态加载模块或包
# __ import __ ( )语法如下
__import__(name,globals,locals,fromlist,level)
参数:name是必填s
8、打包模块与包
- Python的内置模块包setuptools可以将自定义的模块或包打包成 .whl
# 使用内置模块包setuptools的函数方法setup()创建打包文件
from setuptools import setup
setup(
name='mypack'
version='1.0'
py_modules=['a','b','c']
author='xxx'
install_requires=[]
packages=['mys']
)
- 执行打包文件
# 必须安装wheel模块
pip install wheel
# 执行打包命令
python setup.py sdist bdist_wheel
9、安装第三方模块和包
- Python提供了pip管理工具来管理第三方模块或包,它提供了对模块或包的查找、下载、安装、卸载等功能
# install指令语法
# 查看install指令的帮助信息
# pip install -help
# 示例
# 默认安装新版本的模块或包
# 如果安装的模块或包依赖其他模块或包,install指令就会将相关依赖一并安装
# pip install django
# 安装指定版本的模块或包
# pip install django==3.0.8
# 安装.whl文件
# install后面最好写上文件的绝对路径
# 如果PyCharm的Terminal或CMD窗口的当前路径下含有.whl文件,那么可以输入.whl文件的相对路径
# pip install C:\xxx.whl
# download指令语法
# 查看download指令的帮助信息
# pip download -help
# 示例
# 默认下载新版本的模块或包
# 如果下载的模块或包依赖其他模块或包,download指令就会将相关依赖一并下载
# pip download requests
# 下载指定版本的模块或包
# pip download requests==2.17.3
# uninstall指令语法
# 查看uninstall指令的帮助信息
# pip uninstall -help
# 示例
# 卸载已安装的模块或包
# pip uninstall django
# 卸载尚未安装的模块或包,程序提示模块或包尚未安装
# 提示:WARNING: Skipping abc as it is not installed
# pip uninstall abc
# list指令语法
# 查看list指令的帮助信息
# pip list -help
# 示例
# 查看当前已安装的模块或包
# pip list
- pip管理工具除了安装,还能迁移Python开发环境
# pip管理工具提供了freeze指令,将当前环境安装的第三方模块或包的信息写入requirements.txt
# 在新环境中,只需要使用install执行requirements.txt文件,pip管理工具会根据文件记录执行相应的安装命令
# 打包安装文件信息
freeze > requirements.txt
# 执行安装命令
pip install -r requirements.txt