day4之装饰器进阶、生成器迭代器
装饰器进阶
带参数的装饰器
# 某一种情况
# 500个函数加装饰器, 加完后不想再加这个装饰器, 再过一个季度,又想加上去
# 你可以设计你的装饰器,来确认是否执行
# 第一种情况
# 想要500个函数执行装饰器的话,可以定义个变量flag
# Flag = False
# import time
# def outer(flag):
# def timer(f):
# def inner(*args, **kwargs):
# if flag == True: #如果flag==ture,装饰器函数执行
# start_time = time.time()
# ret = f(*args, **kwargs)
# end_time = time.time()
# print(end_time - start_time)
# else: #否则不执行
# ret = f(*args, **kwargs)
# return ret
# return inner
# return timer
#
# @outer(Flag) #最核心的地方,先执行outer(flag)== timer, 相当于@timer
# def func(a, b):
# time.sleep(0.1)
# print(666)
# func(1, 2)
带参数的装饰器
多装饰器装饰同一个函数
# 第二种情况,多装饰器装饰一个函数
# 装饰器 登录 记录日志
# login_info = {'alex': False} # def wrapper1(func): #3 func = f
# def inner1():
# print('wrapper1 ,before func') #14
# func() #15 f()
# print('wrapper1 ,after func') #17
# return inner1 #4 返回inner1
#
# def wrapper2(func): #7 func = inner1,
# def inner2(): #11
# print('wrapper2 ,before func') #12
# func() #13 inner1()
# print('wrapper2 ,after func') #18
# return inner2 #8 return inner2
#
# @wrapper2 #6 f = wrapper2(f'-->inner1') = wrapper1(inner1) 9 f = inner2
# @wrapper1 #2 f = wrapper1(f) 5 f = inner1
# def f(): #1
# print('in f') #16
#
# f() #10 inner2()
多装饰器装饰同一函数
生成器和迭代器
迭代器
python中的for循环
for i in [1,2,3,4]:
print(i)
换一种情况
for i in 1234:
print(i)
TypeError: 'int' object is not iterable
说int类型不是一个iterable
迭代和可迭代协议
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。
可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。
想要可迭代的内部必须有个__iter__方法
__iter__ 都做了些什么
print('asdasd'.__iter__())
结果:
# <str_iterator object at 0x00000000021E7320>
通过 __iter__ 方法,我们得到了个iterator对象
iterator 叫做迭代器
# print(dir([1, 2, 3, 4].__iter__))
'''
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__objclass__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']
'''
迭代器协议
内部含有__iter__和__next__方法的都是迭代器
迭代器内部多了个__next__() 方法
l1_iter = [1, 2, 3, 4].__iter__()
print(l1_iter.__next__())
print(l1_iter.__next__())
print(l1_iter.__next__())
print(l1_iter.__next__())
print(l1_iter.__next__()) #StopIteration
#
结果:
StopIteration
1
2
3
4
__next__
我们一直取next取到迭代器里已经没有元素了,就会抛出一个异常StopIteration,告诉我们,列表中已经没有有效的元素了。
这个时候,我们就要使用异常处理机制来把这个异常处理掉
l = [1,2,3,4]
l_iter = l.__iter__()
while True:
try:
item = l_iter.__next__()
print(item)
except StopIteration:
break
迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
range()
# py2 range,不管range多少, 会生成一个list,这个列表存储所以值
# py3 range, 不管range多少,都不会生成实际的任何一个值,只有在找他要值的时候才会没要一个值,生成一个值
print('__next__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__
print('__iter__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__ from collections import Iterator
print(isinstance(range(100000000),Iterator)) #验证range执行之后得到的结果不是一个迭代器
# __next__() == next()
# __iter__() == iter()
# 坑
# l = [1, 2, 3]
# while True:
# l1 = iter(l)
# print(next(l1))
# while 每次循环都会生成一个新的迭代器对象,所以每次取值都是第一值
# 迭代器节省内存的例子
'''
f = open()
for i in f:
print i
g.close()
'''
# 列表, 字典, 元组, 字符串, 集合,range,文件句柄
# 可要是可迭代的对象,就可以通过iter方法转换为迭代器
生成器
# 自己写的迭代器,就是一个生成器
# 两种方法写生成器(迭代器)的机制:生成器函数, 生成器表达式
Python中提供的生成器:
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列
生成器Generator:
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义
生成器函数
一个包含yield关键字的函数就是生成器函数,yield可以为我们从函数中返回值,但是yield又不同于return
调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,
就能推动函数的执行,获取新的返回值。直到函数执行结束。
# def func():
# print(666)
# yield 1
# print(func()) # --><generator object func at 0x0000000002670C50>
# 生成器函数的调用不会触发代码的执行,而是返回一个生成器(迭代器) # g = func()
# next(g) #-->666 # def func():
# print(666)
# yield 1
# print(777)
# yield 2
#
# g = func()
# print('--', next(g))
# print('--', next(g))
# yield记录当前所在的位置, 等待下次next来触发函数的状态
# 想要生成器函数执行,需要用next
初始生成器函数
更多应用
# 使用生成器监听文件输入的例子
# import time
# def listen_file():
# with open('11.txt') as f:
# while True:
# line = f.readline() #这个位置不用fot循环的原因,是因为for知道文件什么时候结束,readline不知道文件结束,会一直去读
# if line.strip():
# yield line
# time.sleep(0.1)
#
# g = listen_file()
# for line in g:
# print(line)
生成器监听文件文件输入的例子
send关键字
# 在执行next的过程中,传递一个参数给生成器函数的内部
# 向生成器中传递值,有一个激活的过程,第一次必须要用next触发这个是生成器 # def func():
# print(66)
# ret1 = yield 1
# print(77, 'ret1:', ret1)
# ret2 = yield 2
# print(88, 'ret2:', ret2)
# ret3 = yield 3
# g = func()
# ret = next(g)
# print(ret)
# g.send('alex')
# g.send('jin-xin')
# g.send('jign') #--》StopIteration
# def average():
# sum_money = 0
# day = 0
# avg = 0
# while True:
# money = yield avg
# sum_money += money
# day += 1
# avg = sum_money / day
#
# g = average()
# next(g)
# print(g.send(200))
# print(g.send(300))
# print(g.send(500))
计算移动平均值的例子
# 预激生成器
# 计算移动平均值
# def average():
# sum_money = 0
# day = 0
# avg = 0
# while True:
# money = yield avg
# sum_money += money
# day += 1
# avg = sum_money / day
#
# g = average()
# next(g) # 预激活
# print(g.send(200))
# print(g.send(300))
# print(g.send(500)) # 目前有个需求省略与激活这一步 # def init(func1):
# def inner(*args, **kwargs):
# ret = func1(*args, **kwargs)
# next(ret)
# return ret
# return inner
#
# @init
# def average():
# sum_money = 0
# day = 0
# avg = 0
# while True:
# money = yield avg
# sum_money += money
# day += 1
# avg = sum_money / day
#
# g = average()
# print(g.send(200))
# print(g.send(300))
# print(g.send(500))
通过装饰器实现预激生成器
列表推导式和生成器表达式
# yield from py3新加的为了简化代码
# 如何从生成器中取值
'''
def generator_func():
for i in range(5):
yield i
for j in 'hello':
yield j ''' # 等价于
'''
yield from range(5) == for i in range(5):yield i
yield from 'hello' == for j in 'ghello':yield j
'''
def generator_func():
yield from range(5)
yield from 'hello'
yield from 简化代码
# g = generator_func()
# 第一种取值方式 next
# 随时都可以停止,最后一次会报错
# print(next(g)) # 第二种方式 for循环
# 从头到尾遍历一次,不遇到break,return 不会停止
# for i in g:
# print(i) # 第三种,list ,tuple
# 该方式会一次性取出所有值,该方法不太好
# print(list(g))
# print(tuple(g))
生成器的取值方式
# 踩到的坑
# g1 = generator_func()
# g2 = generator_func()
# print(g1, g2)
'''
<generator object generator_func at 0x0000000002140C50> <generator object generator_func at 0x0000000002140D00>
可以看出每次生成一个新的生成器对象,所以直接用generator_func()取值的话会有问题
列表推导式
# 找到name中含有两个e的名字
# names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
# ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# print([ n for n_list in names for n in n_list if n.count('e') == 2])
生成器表达式
# g = (i for i in range(30) if i %3 ==0)
# print(g)
# --><generator object <genexpr> at 0x0000000002670C50>
总结:
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
生成器相关的面试题
# 关于生成器的面试题
# def add(n, i):
# return n + i
# def test():
# for i in range(4):
# yield i
#
# g = test()
# for n in [1, 10]:
# g = (add(n, i) for i in g)
'''
# n=1
# g = (add(10, i) for i in for i in [0,1,2,3])
# n = 10
# g = (add(10, i) for i in add(10, i) for i in [0,1,2,3])
# g = (add(10, i) for i in [10,11,12,13])
# g = (20,21,22,23)
'''
# print(list(g)) def add(n, i):
return n + i
def test():
for i in range(4):
yield i g = test()
for n in [1,2,10]:
g = (add(n, i) for i in g)
'''
n=1 g = (add(1, i) for i in test())
n=2 g = (add(2, i) for i in (add(2, i) for i in test()))
n=10 g = (add(10, i) for i in (add(10, i) for i in (add(10, (0,1,2,3)))) )
n=10 g = (add(10, i) for i in (add(10, (10,11,12,13))) )
n=10 g = (add(10, (20,21,22,23))) )
n=10 g = (30,31,32,33)) )
'''
print(list(g))
面试题1
def demo():
for i in range(4):
yield i g=demo() g1=(i for i in g) #已经取完g中的值
g2=(i for i in g1) #取的空列表 print(list(g1))
print(list(g2))
'''
结果:
[0, 1, 2, 3]
[]
'''
面试题2
import os def init(func):
def wrapper(*args,**kwargs):
g=func(*args,**kwargs)
next(g)
return g
return wrapper @init
def list_files(target):
while 1:
dir_to_search=yield
for top_dir,dir,files in os.walk(dir_to_search):
for file in files:
target.send(os.path.join(top_dir,file))
@init
def opener(target):
while 1:
file=yield
fn=open(file)
target.send((file,fn))
@init
def cat(target):
while 1:
file,fn=yield
for line in fn:
target.send((file,line)) @init
def grep(pattern,target):
while 1:
file,line=yield
if pattern in line:
target.send(file)
@init
def printer():
while 1:
file=yield
if file:
print(file) g=list_files(opener(cat(grep('python',printer())))) g.send('/test1') 协程应用:grep -rl /dir tail&grep
面试题3
小结:
# 一个生成器只能取一次
# 生成器在不找它要值的时候,始终不执行
# 当他执行的时候,要以执行时候的所以变量值为准
day4之装饰器进阶、生成器迭代器的更多相关文章
- Python全栈开发之路 【第五篇】:Python基础之函数进阶(装饰器、生成器&迭代器)
本节内容 一.名称空间 又名name space,就是存放名字的地方.举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方. 名称空间共3种,分别如下 ...
- python学习笔记-(八)装饰器、生成器&迭代器
本节课程内容概览: 1.装饰器 2.列表生成式&迭代器&生成器 3.json&pickle数据序列化 1. 装饰器 1.1 定义: 本质上是个函数,功能是装饰其他函数—就是为其 ...
- CSIC_716_20191113【装饰器进阶以及迭代器】
装饰器的进阶主要包含叠加装饰器和有参装饰器 叠加装饰器:在一个被装饰的对象中,添加多个装饰器. 为什么要用叠加装饰器的原因: -每一个新的功能都应该写一个新的装饰器,否则会导致,代码冗余,结构不 ...
- day13.装饰器进阶,迭代器
1.from functools import wraps 这个函数可以保留原来函数的属性 # from functools import wraps def car_time(fun): # @wr ...
- day11 - 15(装饰器、生成器、迭代器、内置函数、推导式)
day11:装饰器(装饰器形成.装饰器作用.@语法糖.原则.固定模式) 装饰器形成:最简单的.有返回值的.有一个参数的.万能参数 函数起的作用:装饰器用于在已经完成的函数前后增加功能 语法糖:使代码变 ...
- Python3基础(4)匿名函数、装饰器、生成器、迭代器、内置函数、json&pickle序列化、软件目录开发规范、不同目录间模块调用
---------------个人学习笔记--------------- ----------------本文作者吴疆-------------- ------点击此处链接至博客园原文------ 1 ...
- python迭代器、装饰器和生成器
装饰器 1.装饰器的作用 1. 装饰器作用:本质是函数(装饰其他函数)就是为其他函数添加其他功能 2. 装饰器必须准寻得原则: 1)不能修改被装饰函数的源代码 2)不能修改被装饰函数的调用方式 3.实 ...
- Python函数--装饰器进阶
开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封 ...
- day 12 - 1 装饰器进阶
装饰器进阶 装饰器的简单回顾 装饰器开发原则:开放封闭原则装饰器的作用:在不改变原函数的调用方式的情况下,在函数的前后添加功能装饰器的本质:闭包函数 装饰器的模式 def wrapper(func): ...
随机推荐
- Java常用的类 包 接口
类 Byte ShortIntegerLong Float Double Boolean CharFile DateThread(java.lang.ThreadThread类的定义:public c ...
- OPTION SQL_SELECT_LIMIT=DEFAULT'
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version ...
- Spring Boot中启动HTTPS
一,生成https 的证书 1,在相应的根目录下 keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize -keyst ...
- Hadoop 3.0.0-alpha1几个值得关注的特性
1.支持纠删码:意味着更灵活的存储策略,即经常使用的数据利用备份方式存储(3倍存储消耗),冷数据利用纠删码容错(1.4倍存储消耗,但会造成额外的IO及CPU消耗): 2.MapReduce任务支持本地 ...
- SmartOS技术常见问题
什么是默认用户名和密码? 当SmartOS Live Image第一次启动时,系统将提示您设置root密码. 如果在不导入Zpool的情况下启动SmartOS,则需要默认的root密码. 当使用noi ...
- C#语法基础
泛型 1.default(T)可以返回T类型的空值,因为你不知道T是值类型还是引用类型,所以别擅自用null 2.泛型约束 很多时候我们不希望使用者太过自由 我们希望他们在使用我们设计的泛型类型时 不 ...
- Linux删除文件名中包含“-”的文件
背景: 练习用shell的一些特殊符号,输出了一个 cat test.txt > -n,结果创建了一个叫做“-n”的文件 问题: 使用rm -f -n删除不了“-n"文件 解决 ...
- OOP的几个不常用的方法
from OOP_多态 import cat c = cat("cat") print(c.__doc__) print(cat.__doc__) # # 打印类的描述信息,也就是 ...
- php Pthread 多线程 (六) Pool类 线程池
Pool对象是多个Worker对象的容器,同时也是它们的控制器,对Worker功能更高抽象. 比如Worker是河,而线程是运行在河里的船.Pool则是管理着多条河. <?php //继承Col ...
- 源码安装php时出现configure: error: xml2-config not found. Please check your libxml2 installation
1.检查是否安装了libxml 包 > rpm -qa|grep libxml2 2.如果没有则安装 > yum install libxml2 > yum install libx ...