1. 迭代器

1.1 可迭代对象(Iterator)

迭代器协议:某对象必须提供一个__next__()方法,执行方法要么返回迭代中的下一项,要么引起一个Stopiteration异常,以终止迭代(只能往后走,不能往前退)

协议是一种规范,可迭代对象实现了迭代器协议,python的内部工具(如for循环、sum、min、max函数),使用迭代器协议访问对象

可迭代对象(Iterator):实现了迭代器协议的对象(如何实现:对象内部定义了一个__iter__()方法),也就是可迭代对象内部要包含__iter__() 函数

迭代器(Iterator):内部包含了__iter()__() ,同时也包含__next__()

1.2 for循环的工作机制

先通过__iter__()方法将可迭代对象转换为迭代器,再调用迭代器中的__next__()方法遍历,最后再抓取结束时的异常

print("解析for循环的工作机制:")
num = [1, 2, 3, 4, 5]
for i in num: # 工作机制: num.__iter__() ------> num.__next__()
print(i)

1.3 可迭代对象与迭代器

1)可迭代对象与迭代器之间的关系

  • 可迭代对象包含迭代器
  • 如果一个对象拥有__iter__方法,其就是可迭代对象(可以被for循环迭代);如果一个对象拥有next方法,其是迭代器
  • 定义可迭代对象,必须事先__iter__方法;定义迭代器,必须实现__iter__和next方法。

2)迭代器的特点

  • 节省内存
  • 惰性机制
  • 不能反复,只能向下执行

3)isinstance()判断对象是否为Iterable对象:

from collections import Iterable
print(isinstance([], Iterable))

1.4 迭代器协议的使用示例

print("使用while循环遍历一个列表:")
index = 0
while index < len(num):
print(num[index])
index += 1 print("利用迭代器协议遍历一个列表:")
iter = num.__iter__()
print(iter.__next__())
print(iter.__next__())
print(iter.__next__()) print("解析文件操作中对于文件内容的遍历:")
f = open("test.txt", "r")
f_iter = f.__iter__() # 这里先将整个文件转换为一个迭代器,之后对迭代器调用__next__()方法,只在有需要的时候才加载文件一行内容
# 当取出一行内容时,因为没有赋值给任何变量,所以占用的内存会被python的自动回收机制回收,所以这种遍历文件的方式只会动态的占用一小块内存
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
f.close() print("next()方法:") # next()方法--->调用__next__()方法
the_num = [1, 2, 3]
the_iter = the_num.__iter__() # 也可以直接使用iter(the_num)方法
print(next(the_iter)) # next(the_iter) -----> 调用 the_iter.__next__()

2. 生成器

2.1 生成器概述(generator)

生成器(generator)就是可迭代对象(它在内部实现了迭代器协议)

生成器在python中的两种表达形式:

  • 生成器表达式
  • 生成器函数

触发生成器的方式:

  • 通过调用__next__()方法,相当于send(None)
  • 通过调用send()方法

2.2 生成器函数

  • 只要函数中包含yield关键字,则此函数就是一个生成器函数
  • 每调用一次 __next__(),yield后面的值就会被返回一次,且保留此次的状态,下一次调用从此位置开始

1)生成器函数

def func():
print("现在开始执行生成器函数:")
print("First----->")
yield "第一步"
print("Second----->")
yield "第二步"
print("Third")
yield "第三步"
print("End")
yield "生成器函数调用完毕" f = func()
print(f.__next__()) # __next__()函数调用接受到的返回值就是yield后面的值
print(f.__next__())
print(f.__next__())
print(f.__next__())

2)用yield方式的生成器实现字典中文件的内容查找

def get_num():
f = open("population.txt", "r", encoding="utf-8") # 这个文件中的每一行都是一个字典
for i in f:
yield i # 这里返回的 i 为字符串类型 population = eval(get_num().__next__()) # 这里通过eval()函数重新恢复了文件中数据的数据类型,恢复成了字典
print("%s的人口数为%s" % (population["city"], population["population"]))
# 注意:生成器只能遍历一次 # 用生成器表达式的方式实现字典中文件数字的求和
f = open("population.txt", "r", encoding="utf-8")
p = sum(eval(i)["population"] for i in f)
print(p)

3)send()方法的使用

def my_func():
print("First")
send1 = yield 1 # yield后面的值是next方法调用的返回值,而前面的值是yield接收值之后赋值的变量
print("Second")
print("此次send传送的值为:", send1)
send2 = yield 2
print("Third")
print("此次send传送的值为:", send2)
yield 3
print("End") m = my_func() # 这里并不会执行这个函数,因为只要函数内部定义了yield关键字,函数就变成了生成器,只有通过next方法调用
print(m.__next__()) print(m.send(None) ) # 这里的send(None),就相当于__next__()方法,触发一次生成器
# send()函数将值传递给当前停留位置的yield,之后这个yield会将值传递给前面的变量
print(m.send("这是第二次send"))

4)yield from

  • yield from可以直接把迭代对象中的每一个数据作为生成器的结果进行返回
  • 因为yield from是将列表中的每一个元素返回,所以写两个yield from并不会产生交替的效果
def func():
lst1 = ['卫龙','老冰棍','北冰洋','牛羊配']
lst2 = ['馒头','花卷','豆包','大饼']
yield from lst1
yield from lst2
g = func()
for i in g:
print(i) # 卫龙
# 老冰棍
# 北冰洋
# 牛羊配
# 馒头
# 花卷
# 豆包
# 大饼

5)额外

def func3():
for i in range(10):
yield i t = func3()
# for i in t: # 因为for循环的工作机制就是使用迭代器协议调用next方法,所以会触发生成器函数
# print(i) li1 = (i for i in t) # 这里li1会得到一个生成器的地址
li2 = (i for i in li1)
print(type(li1))
print(list(li1)) # 这里的list函数中会用for循环机制取值,从而触发生成器,现在这个位置li1中的值已经被取完了
print(list(li2)) # 因li1中的值已经被取完了,所以li2现在已经取不到值了

2.3 推导式

  • 推导式有:列表推导式、字典推导式、集合推导式
  • 没有元组推导式

1)列表推导式

  • 三元表达式

    name = "hgzero"
    ret = "me" if name == "hgzero" else "other" # 若name等于hgzero,则返回me,否则返回other
    print(ret)
  • 列表推导式(列表解析)

    list1 = [i for i in range(10)]                 # 列表解析会将生成的列表直接放于内存中,会占用较大的内存
    print(list1)
    list2 = ["数字%d" % i for i in range(10)] # for循环处理后将i依次往前面传递
    print(list2)
  • 筛选模式(三元表达式和列表解析的使用示例)

    print("三元表达式和列表解析结合")
    list3 = ["数字%d" % i for i in range(10) if i > 5] # 这里不能使用else,因为已经构成了三元表达式了
    print(list3)

2)生成器推导式

  • 将列表推导式外围的中括号换成小括号就变成了一个生成器推导式
  • 生成器推导式也可以使用筛选模式
print("生成器表达式:")
list2 = ("数字%d" % i for i in range(10)) # 将列表解析表达式外围的中括号换成小括号就变成了一个生成器
# 生成器表达式更节省内存
print(list2)
print(list2.__next__())
print(list2.__next__())
print(list2.__next__())
print(list2.__next__()) # 可以将生成器表达式传递给sum()等函数,以节省占用内存的大小
print(sum(i for i in range(100000)))
# 这里的sum函数里面的生成器表达式不需要加括号
# 如果直接在sum中传入一个非常大的列表,会造成占用太多内存而导致机器卡死,而用生成器的方式传入则会动态的占用很小的一片内存

3)字典推导式

lst1 = ['jay','jj','huazai']
lst2 = ['周杰伦','林俊杰','刘德华']
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic)

4)集合推导式

  • 集合推导式可以直接生成一个集合
  • 集合的特点:无需、不重复,所以集合推导式自带去重功能
lst = [1,2,3,-1,-3,-7,9]
s = {abs(i) for i in lst}
print(s)

2.4 生产者消费者模型

import time

# def producer():
# ret = []
# for i in range(100):
# time.sleep(0.1)
# ret.append("包子%s" % i)
# return ret
#
# def consumer(ret):
# for index, baozi in enumerate(ret):
# time.sleep(0.1)
# print("第%d个人来了,吃了第%s个包子" % (index, baozi))
#
# p = producer()
# consumer(p) def producer():
c1 = consumer("hgzero")
c2 = consumer("wuzhihao")
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(1)
print("现在包子 %s 已经做好了!" % i)
c1.send("第%s个包子" % i)
c2.send("第%s个包子" % i) def consumer(name):
print("吃包子开始!")
while True:
baozi = yield
time.sleep(1)
print("我是 %s , 现在开始吃 %s 包子" % (name, baozi)) producer()

2.5 闭包

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用,这样就构成了一个闭包。简单来说,闭包就是内层函数,对外层函数变量的引用。

一般情况下,如果一个函数执行结束,则这个函数的内部的变量以及局部命名空间中的内容都会被释放掉。但是在闭包中,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。也就说,使用闭包,可以保证外部函数中的变量在内存中常驻,以供后面的程序使用。

其实闭包中外部函数的返回值定义成内部函数的地址,是为了防止内部函数被垃圾回收机制回收。

def func1():
def func2():
s = '地主家的傻儿子'
def func3():
print(s)
return func3
return func2
func1()()()

2.6 解压序列

# 解压序列:
a, *b, c = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 这里的 * 号表示所有的意思
print(a)
print(b)
print(c) # 交换两个变量的值:
a = 1
b = 2
print("通过中间变量的形式交换:")
c = a
a = b
b = c
print(a, b) print("另外两种不引入额外变量实现交换的方式:")
f1 = 1
f2 = 2
f1, f2 = f2, f1
print(f1, f2) n1 = 1
n2 = 2
n1 = n1 + n2
n2 = n1 - n2
n1 = n1 - n2
print(n1, n2)

3. 装饰器

3.1 装饰器概述

  • 装饰器:本质上就是函数,功能是为其他函数添加附加功能
  • 原则:
    • 不修改被修饰函数的源代码
    • 不修改被修饰函数的调用方法
  • 装饰器 = 高阶函数 + 函数嵌套 + 闭包

3.2 装饰器的实现方式

1)用高阶函数的方式实现装饰器的功能:不合格,因为这种方式会使工作函数调用了两次

#    1.不修改被修饰函数的源代码
# 2. 不修改被修饰函数的调用方式 # 装饰器 = 高阶函数+函数嵌套+闭包
import time # 用高阶函数的形式想实现装饰器的功能,不合格,因为这种方式会使工作函数调用了两次
def work_func():
time.sleep(1)
print("这里是work_func函数") def dec_func(func):
start_time = time.time()
func()
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time-start_time))
return func work_func = dec_func(work_func) # 这里在赋值之前就已经执行了dec_func(work_func)函数
work_func() # 这里又执行了一便work_func函数

2)用高阶函数 + 函数嵌套 + 闭包的方式实现装饰器

import time
def work_func2():
time.sleep(1)
print("这里是work_func2函数") def dec_func2(func):
def wapper():
start_time = time.time()
func()
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time - start_time))
return wapper work_func2 = dec_func2(work_func2) # 这里执行dec_func2函数时遭遇一个闭包,得到的是闭包wrapper函数的内存地址(并没有执行它)
work_func2() # 这里执行上面得到的闭包函数,即执行wapper()函数

3)用“语法糖”的形式实现装饰器

import time
def dec_func3(func):
def wapper():
start_time = time.time()
func()
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time - start_time))
return wapper @dec_func3 # 用“语法糖”的形式实现装饰器 ,相当于 work_func3 = dec_func3(work_func3)
def work_func3():
time.sleep(1)
print("这里是work_func3函数")
work_func3() def dec_func4(func): # 装饰器改进,添加返回值和多参数功能
def wapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs) # func()函数的返回值就是work_func函数中的返回值,用res接收之后,再返回出去
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time - start_time))
return res
return wapper @dec_func4 # work_func4 = dec_func3(work_func3) 这时执行work_func4函数就是执行wapper函数,因为dec_func3函数返回的就是wapper的地址
def work_func4(name, age):
time.sleep(1)
print("这里是work_func4函数")
print("Name:【%s】,Age:【%d】" % (name, age))
return 12345 # 这时,work_func函数的返回值就是dec_func函数的闭包---> wapper函数的返回值
work_func4("hgzero", 21)

3.3 带认证功能的装饰器

import time

user = [
{"username": "hgzero", "passwd": "123"},
{"username": "wzh", "passwd": "123"},
{"username": "hg", "passwd": "123"},
{"username": "zero", "passwd": "123"},
{"username": "abc", "passwd": "123"}
] login_dict = {"username": None, "login": False} # 这里用这个字典模拟session的功能 def login_func(func):
def wrapper(*args, **kwargs):
if login_dict["username"] and login_dict["login"]:
ret = func(*args, **kwargs)
return ret
while True:
username = input("请输入用户名:").strip()
passwd = input("请输入密码:").strip()
for dict in user:
if dict["username"] == username and dict["passwd"] == passwd:
login_dict["username"] = username
login_dict["login"] = True
ret = func(*args, **kwargs)
return ret
else:
print("用户名或密码错误!")
time.sleep(1)
print("请重新输入----->")
return wrapper @login_func
def index():
print("欢迎来到zero的网站主页!") @login_func
def home(name):
print("【%s】,欢迎来到个人中心!" % (name)) @login_func
def shopping(name):
print("【%s】,现在您的购物车中有 %s , %s , %s " % (name, "牛奶", "香蕉", "芒果")) index()
home("python工程师")
shopping("python工程师")

3.4 带参数的装饰器

import time
user = [
{"username": "hgzero", "passwd": "123"},
{"username": "wzh", "passwd": "123"},
{"username": "hg", "passwd": "123"},
{"username": "zero", "passwd": "123"},
{"username": "abc", "passwd": "123"}
] login_dict = {"username": None, "login": False} # 这里用这个字典模拟session的功能 def func(db_type):
def login_func(func):
print("这个数据库的类型是:", db_type)
def wrapper(*args, **kwargs):
if login_dict["username"] and login_dict["login"]:
ret = func(*args, **kwargs)
return ret
while True:
username = input("请输入用户名:").strip()
passwd = input("请输入密码:").strip()
for dict in user:
if dict["username"] == username and dict["passwd"] == passwd:
login_dict["username"] = username
login_dict["login"] = True
ret = func(*args, **kwargs)
return ret
else:
print("用户名或密码错误!")
time.sleep(1)
print("请重新输入----->")
return wrapper
return login_func @func("MySQL") # 这里先执行func("MySQL") ---> index = login_func(index)
# 这里因为后面加了括号,所以是执行了func函数,执行了func函数所得到的返回值就是login_func函数的地址
# func()函数执行得到的地址就是login_func,所以这里就等价于是 @login_func,同时也将参数传进去了,巧妙的运用了闭包的原理
def index():
print("欢迎来到zero的网站主页!") @func("Mongodb")
def home(name):
print("【%s】,欢迎来到个人中心!" % (name)) @func("Redis")
def shopping(name):
print("【%s】,现在您的购物车中有 %s , %s , %s " % (name, "牛奶", "香蕉", "芒果")) index()
home("python工程师")
shopping("python工程师")

Python迭代器&生成器&装饰器的更多相关文章

  1. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  2. 4.python迭代器生成器装饰器

    容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...

  3. Python迭代器,生成器,装饰器

    迭代器 通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结果作为下一次迭代的初始值). 可迭代对象(iterable):是指该对象可以被 ...

  4. Python(迭代器 生成器 装饰器 递归 斐波那契数列)

    1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...

  5. Python基础-迭代器&生成器&装饰器

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...

  6. 迭代器/生成器/装饰器 /Json & pickle 数据序列化

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  7. Day04 - Python 迭代器、装饰器、软件开发规范

    1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...

  8. python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化

    生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...

  9. python中的迭代器&&生成器&&装饰器

    迭代器iterator 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外, ...

随机推荐

  1. Ubuntu18.04上安装CUDA_10.1(nvidia-driver)和cuDNN_7.6.5

    本文是在Ubuntu18.04.5服务器上安装CUDA_10.1(nvidia-driver455)和cuDNN_7.6.5, Ubuntu 18.04.5 CUDA_10.1 (nvidia-dri ...

  2. mybatis insert转update,duplicate关键字的使用示例,及返回情况说明

    主键存在时又insert转为update某个关键字段,示例如下,注意,如果这条数据曾经不存在,此时执行insert返回条目是1,如果已存在,执行update返回条目是2!!!<insert id ...

  3. [LeetCode题解]876. 链表的中间结点 | 快慢指针

    解题思路 使用快慢指针.这里要注意的是,while 的条件会影响当中间节点有两个时,slow 指向的是第一个,还是第二个节点. // 返回的是第一个 while(fast.next != null & ...

  4. 深入理解r2dbc-mysql

    目录 简介 r2dbc-mysql的maven依赖 创建connectionFactory 使用MySqlConnectionFactory创建connection 执行statement 执行事务 ...

  5. hackrf GPS欺骗

    在对GPS欺骗之前,先对GPS的知识做一个简单的介绍 GPS 系统本身非常复杂, 涉及到卫星通信等各个领域. 这里只是简单介绍一下. 我们通常所说的 GPS 全球定位系统是由美国国防部建造完成. 目前 ...

  6. go编译成exe后,打开出现闪退问题

    今天博主编译了一个go小脚本,编译完成后用自己电脑试了一下没有问题 然而,当换了一台电脑后,一样是win7系统64位,出现了闪退 于是乎博主疯狂百度 看到网上说   入口文件 的顶部改成  packa ...

  7. nginx转发php文件到php-fpm服务器提示502错误

    实验将php文件转发给另一个php-fpm服务器处理的时候,出现了502错误: 检查了nginx错误日志,提示: 2019/08/25 17:54:56 [error] 4742#0: *35 rec ...

  8. 「CSP-S 2019」划分

    description loj 3212 solution 首先容易想到\(n^3\)DP,即令\(f_{i,j}\)表示前\(i\)个数的划分,其中最后一段是从\(j\)开始时的答案 于是有 \[f ...

  9. C++ cout格式化输出完全攻略

    写算法题的时候突然发现自己忘记基本的C++:cout格式化输出了,赶紧拉出以前的C++学习笔记重新看一看. 部分内容来自教程:C语言中文网(一个很棒的网站) 有时希望按照一定的格式进行输出,如按十六进 ...

  10. jmeter测试udp

    jemter本身不支持udp测试,需要下载安装第三方插件,或者下载一个插件管理器(下面那个蝴蝶一样的图标),里面有各种插件可以供你下载 下载链接:https://jmeter-plugins.org/ ...