一、装饰器
'''
装饰器:就是闭包(闭包的一个应用场景)
-- 把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数
优点:
-- 丰富了原有函数的功能
-- 提高了程序的可拓展性
'''
开放封闭原则
'''
1.不能修改被装饰对象(函数)的源代码
2.不能更改被修饰对象(函数)的调用方式
'''
装饰器的简单实现
def outer(func):
def inner():
print("新增功能1")
func()
print("新增功能2")
return inner
def func():
print("原有功能")
func = outer(func)
装饰器语法糖
def outer(func):
def inner():
print("新增功能1")
func()
print("新增功能2")
return inner
@outer
def func():
print("原有功能")
装饰有参有返的函数
def outer(func):
def inner(*args, **kwargs):
print("新增功能1")
result = func(*args, **kwargs)
print("新增功能2")
return result
return inner
@outer
def func(*args, **kwargs):
print("原有功能")
return "原有结果"
有参装饰器
def wrap(arg):
def outer(func):
def inner(*args, **kwargs):
print("新增功能1")
result = func(*args, **kwargs)
print("新增功能2")
return result
return inner
@wrap("装饰器参数")
def func(*args, **kwargs):
print("原有功能")
return "原有结果"
wraps修改函数文档注释
from functools import wraps
def outer(func):
@wraps(func)
def inner(*args, **kwargs):
'''装饰器文档注释'''
func(*args, **kwargs)
return inner
@outer
def func(*args, **kwargs):
'''原有文档注释'''
print("原有功能")
二、迭代器
# 迭代器:循环反馈的容器(集合类型)
# -- 不同于索引取值,但也可以循环的从容器对象中从前往后逐个返回内部的值
# 优点:不依赖索引,完成取值
# 缺点:不能计算长度,不能指定位取值(只能从前往后逐一取值)
可迭代对象
# 可迭代对象:内置有__iter__()方法的对象,称之为可迭代对象
# 可迭代对象:str | list | tuple | set | dict | range() | enumerate() | file | 生成器对象
迭代器对象
# 迭代器对象:内置有__next__()方法的对象,称之为迭代器对象,可以通过调用__next__()方法完成取值
# 迭代器对象:enumerate() | file | 生成器对象
# 注:迭代器对象调用__iter__()方法返回的还是迭代器对象
迭代器
# 迭代器:for循环
# 工作原理:
# -- 1.获取可迭代对象的迭代器对象
# -- 2.循环__next__()取值
# -- 3.异常处理(StopIteration),停止迭代
生成器
# 生成器:一次生成一个值得容器(函数类型)
# -- 内部包含yield关键字的函数
# 注:函数的调用不会执行函数,而是返回生成器对象
生成器对象
# 生成器对象:就是一个迭代器对象
# -- 可以通过__next__()方法取值,得到yield关键字的返回值
# -- 可以调用send()方法给yield关键字传值,内部接收yield关键字可以得到传入的值
枚举对象
# 枚举对象:通过enumerate()方法,可以为可迭代对象生成迭代索引,其本身也是一个迭代器对象
三、知识点补充
三元表达式
# 结果1 if 条件 else 结果2
列表推导式
[i for i in range(10)]
字典推导式
{k, v for k, v in enumerate('abc')}
四、递归
# 函数的直接或间接自调用
五、内置函数
匿名函数
# lambda 参数1, ..., 参数n: 返回值
内置函数
# https://docs.python.org/zh-cn/3.7/library/functions.html
六、模块与包
模块
'''
模块:一系列功能的集合体
常见的四种模块:
1.使用python编写的.py文件
2.把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
3.使用C编写并链接到python解释器的内置模块
4.已被编译为共享库或DLL的C或C++扩展
'''
模块的搜索路径
'''
搜索顺序:内存 => 内置模块 => sys.path
1.导入模块会优先在内存中查找
2.内存中没有被加载的话,再去查找内置模块
3.还没有查找到,就根据sys.path中的路径顺序逐一查找
'''
模块导入的执行流程
'''
导入模块的指令:
-- 相对于 函数名() 调用函数体,函数调用会进入函数体,从上至下逐句解释执行函数体代码
-- 导入模块,会进入模块文件,从上至下逐句解释执行模块文件代码
-- 如果在模块中又遇到导入其他模块,会接着进入导入的模块,从上至下逐句解释执行文件中代码,依次类推
'''
循环导入
'''
模块之间出现了环状导入,如:m1.py 中导入了m2,m2.py 中又导入了m1
循环导入的问题:
-- 导入模块是要使用模块中的变量
-- 正常逻辑都是在文件最上方先完成对模块的导入,再在下方定义自身模块变量,以及使用导入的模块中的变量
-- 由于导入模块的特殊机制,第一次导入模块会编译执行导入的模块,也就是会进入模块逐句执行模块内容,再次导入只是使用内存中的名字
-- 就会出现下面的情况,m2在使用m1中的变量x,但变量x却并未产生,这就出现了循环导入问题
m1.py文件
import m2
x = 10
print(m2.y)
m2.py文件
import m1
y = 10
print(m2.x)
解决循环导入的问题:延后导入
1、将循环导入对应包要使用的变量提前定义,再导入响应的包
2、将导包的路径放倒函数体中,保证存放导包逻辑的函数调用在要使用的变量定义之后
重点:
问题:from导包极容易出现循环导入问题
解决:取消from导入方式,采用import导入方式
'''
包
'''
一系列功能模块的集合体
-- 包就是管理功能相近的一系列模块的文件夹
-- 该文件夹包含一个特殊文件__init__.py
-- 文件夹名就是包名,产生的包名就是指向__init__.py的全局名称空间
导包完成的三项事:
1.编译执行包中的__init__.py文件,会在包中__pycache__创建对应的pyc文件
2.产生__init__.py文件的全局名称空间,用来存放__init__出现的名字
3.产生包名指向__init__.py文件的全局名称空间 | 指定变量名指向包中指定名字
'''
包中模块的使用:import
'''
module文件夹
-- __init__.py
-- m1.py
test.py文件
import module
# 在该文件中使用包
'''
# 1.__init__.py文件中产生的普通名字可以直接使用
'''
__init__.py
x = 10
test.py
print(module.x)
'''
# 2.管理的模块中出现的名字,要通过 包名.模块名 间接使用
'''
m1.py
num = 10
__init__.py
import module.m1
test.py
print(module.m1.num)
'''
包的嵌套
# 在包中再定义包
# 连包的导入
import 父包.子包
# 重点:导包的.语法,在所有点左侧都必须是包
# 正确案例:
import 父包.子包
import 父包.子包.模块
# 错误案例
import 父包.子包.模块.名字
包中模块的使用:from...import
'''
使用规则与import差不多,但是导包的.语法需严格执行,就是所有点左侧都必须是包
'''
导包的两种方式
# 绝对导入:通过sys.path方式来实现
# 相对导入:通过包内.语法来实现
绝对导入
# 将对应的文件夹添加至sys.path中,就可以直接导入对应文件夹下的模块
相对导入
# 相对导入是存在于包内的语法
# .代表当前文件夹
# ..代表上一级文件夹
# 存在.语法的文件,不能作为执行文件