什么是迭代器,生成器,装饰器;django的信号用过吗?如何用,干过什么;什么是深拷贝,什么是浅拷贝,如何使用
什么是迭代器,生成器,装饰器
# 迭代器
- 迭代:一种不依赖于索引取值的方式,我们不需要关注它的位置,只要能够一个个取值,它就称之为迭代,python中就是for循环,内部调用对象.__next__()
- 可迭代对象:python中可以被for循环的对象或可以变量.__next__()取值即为可迭代对象;str, list, dict, tuple, set, 文件对象都是可迭代对象
- 迭代器:可迭代对象调用__iter__()就得到了迭代器,迭代器有__iter__和__next__方法
- 自定义迭代器:写个类,类中重写__iter__和__next__方法,这个类的对象就是迭代器
下面是一个示例,展示如何在Python中自定义迭代器:
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
这个自定义迭代器接受一个数据列表作为参数,并使用data属性来存储数据。初始化时,设置index为0来追踪当前迭代到哪个位置。
__iter__方法返回迭代器对象本身,这是迭代器模式的标准实现。
__next__方法用于获取下一个元素。如果index超过了数据列表的长度,那么抛出StopIteration异常来停止迭代。否则,返回当前索引位置的值,并将index增加1以准备迭代到下一个元素。
下面是使用自定义迭代器的示例:
pythonCopymy_list = [1, 2, 3, 4, 5]
my_iter = MyIterator(my_list)
for element in my_iter:
print(element)
输出:
1
2
3
4
5
这样,我们就可以根据自己的需求定义迭代器,实现按照特定规则和顺序进行迭代。
'''
1.文件对象即是可迭代对象又是迭代器对象
2.迭代器一定是可迭代对象,可迭代对象不一定是迭代器
3.当元素被取完的时候,再去利用__next__取值,会抛出异常
迭代取值
1.只能从前往后挨个取值,不能倒回去,除非重新生成一个新的迭代器
2.支持所有数据类型
索引取值
1.重复取值
2.不支持所有的数据类型,支持可以索引取值(列表、元组、字符串)的数据类型
'''
# 生成器
- 生成器就是迭代器的一种,生成器一定是迭代器,迭代器不一定是生成器
- 函数中如果存在 yield 关键字,在调用函数之前,还是一个普通函数,一旦调用函数,就把函数变成了生成器
- 生成器表达式,也可以做出生成器 (i+1 for i in [1,2,3])
比如有一堆数据,要放到列表中,但你没放,而放到了生成器中
for 循环生成器---》可以惰性取值(不是把值一次性放在某一个可迭代对象里,而是循环一次取一个),可以节省内存
- 代码遇到 yield 关键字,会被冻结,再次执行 next() ,代码从上一次被冻结的位置继续往下执行
- yield 和 return 的对比
'''
yield
1. 可以有返回值
2. 函数遇到yield不会结束,只会'冻结'
3. yield关键字把函数变成了生成器,支持迭代取值了
return
1. 可以有返回值
2. 遇到return关键字直接结束函数运行
'''
- 在哪里用过生成器?
1.读取文件,for循环内部其实就是在用生成器
2.django中orm查询一个表所有内容 Book.objects.all()--->内部应该也是一个生成器
3.redis中hash类型hscan 和 hscan_iter
4.类似于这种场景我是可以用到它的:比如我要取数据,但是数据量比较大,不要一次性把把数据取到内存中,而是一点点取值,这样就可以把它做成一个生成器,可以节约内存
# 装饰器
- 名称空间:存放变量值和变量名关系的地方
内置的名称空间:在python解释器中存在
全局的名称空间:在py文件中,顶格写的代码都在全局名称空间中 查看:print(globals()) # 字典形式
局部的名称空间:在函数体代码执行完产生的数据 查看:print(locals()) # 一定写在函数内部
- 闭包函数:
闭:定义在函数内部的函数
包:内部函数使用外部函数名称空间中得名字
多了一种给函数传参的方式
- 装饰器,本身是一个闭包函数
在不改变被装饰对象的内部代码和原有调用方式的基础上再添加额外的功能
- 运用场景
flask的路由就是基于装饰器
django的信号也可以用装饰器方式注册
django中局部去除csrf认证
为接口记录访问日志
认证。。
- 语法糖
每次调用函数都要写2行很别扭,引入语法糖
书写规范:
1.语法糖要紧贴再被装饰对象的头上
2.原理:把紧贴着的被装饰对象自动传给装饰器函数
- 双层语法糖
写的时候从上往下写,执行的原理是从下往上,实际执行是从上往下
调用的时候虽然名字一样,但是并不是原函数,被装饰器伪装了,实际是最上层语法糖的返回值
- 装饰器修复技术
print(func_name)打印函数名和help(func_name)可以帮助看清本质
from functools import wraps
'在装饰器outer函数里写'
@wraps(func_name) # 为了让被装饰对象不容易被察觉
'再help(index)就查找不到本质,被伪装了
- 有参装饰器
在无参装饰器外面再包一层来装参数
@outer('file')函数名遇到括号优先级最高,先执行outer('file'),然后@+返回结果,又变成双层装饰器,外面包一层仅仅是为了传参
假如还需要参数,不需要再包,直接再外面的函数括号李传参,就是普通函数传参
django的信号用过吗?如何用,干过什么
什么是深拷贝,什么是浅拷贝,如何使用
