什么是迭代器,生成器,装饰器;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的信号用过吗?如何用,干过什么
# Django提供的一种通知机制,他是设计模式观察者模式(发布订阅),在发生某种变化的时候,通知某个函数执行
- 23种设计模式
1.装饰器模式————装饰器
2.迭代器模式————迭代器,不依赖索引取值从容器对象中访问一个个元素,还不暴露对象的内部细节
3.代理模式————真正用一个东西时,没有使用该东西,而是让代理去拿;flask中的request就是代理对象,真正的对象在后面藏着。通过一个代理对象来控制对实际对象的访问
4.[单例模式](https://www.cnblogs.com/10086upup/p/17606300.html)
5.观察者模式————观察者模式也叫发布-订阅模式,其定义如下:
定义对象间一种一对多的依赖关系,使得当该对象状态改变时,所有依赖于它的对象都会得到通知,并被自动更新。运用在Django的信号中
https://www.cnblogs.com/liuqingzheng/p/10038958.html
- 内置信号
内置信号用起来简单,只需要写个函数,跟内置信号绑定,当信号被触发,函数就会执行
- 使用方式:2种
1.connect连接
2.使用装饰器@receiver
# 当User表创建用户,记录日志
# 方式一
1.写一个函数,放在__init__里,因为代码要执行
from django.db.models.signals import post_save
import logging
def callback(sender,**kwargs):
logging.debug('%s创建了一个%s对象'% (sender._meta.,odel_name,kwargs.get('instance').title))
2.绑定内置信号
post_save.connect(callback)
3.等待触发
# 方式二 使用装饰器
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished) # 本质就是用了connect
def my_callback(sender, **kwargs):
print("Request finished!")
- 自定义信号
1.定义信号(一般创建一个py文件)
import django.dispatch
pizza_done = django.dispatch.Signal( providing_args=["toppings", "size"])
2.绑定信号
def callback(sender,**kwargs):
print('callback')
print(sender,kwargs)
pizza_done.connect(callback)
3.触发信号: 信号.send
from 路径 import pizza_done
pizza_done.send(sender='seven',toppings=123, size=456)
# 信号发送者sender
https://www.cnblogs.com/liuqingzheng/articles/9803403.html
# 应用场景
- 记录日志
- 做双写一致性的缓存更新(据库中插入数据,把数据同步到别的位置)
- 一旦生成订单,发送邮件
- 用户删除发短信通知
- 用户修改密码,发信号让token失效
什么是深拷贝,什么是浅拷贝,如何使用
# 无论深拷贝还是浅拷贝都是用来复制对象的
# 如果是浅copy,只会复制一层,如果copy的对象中有可变数据类型,修改可变数据类型还会影响拷贝的对象。浅copy,不可变数据类型,无论是=还是使用浅copy都不能对数据进行复制申请新的内存空间,只是同时指向了同一个内存空间。
# 如果是深copy,完整复制,无论可变或不可变,都是创建出新的来,以后再改原对象,都不会对copy出的对象造成影响
https://www.cnblogs.com/lmygbl/p/10124827.html
标签:__,函数,迭代,对象,什么,生成器,拷贝,装饰
From: https://www.cnblogs.com/10086upup/p/17621233.html