Python基础语法八——迭代器&生成器&装饰器

一,迭代器
可迭代对象:通俗理解,可以被for的对象。实际上,python协议中有:具有__iter__方法的就是可迭代对象
  obj.__iter__(),内置容器被请求迭代时,会调用这个方法。
    返回一个能够迭代容器内所有对象的迭代器,obj为字典时,只迭代键。
  iterator.__next__()
    返回容器的下一个元素
a = obj.__iter__() # 创建一个迭代器
a.__next__()  # 一个一个取
具有__iter__和__next__的就是一个迭代器
 
 
迭代器特性
惰性机制
不能逆行
一次性,用完即弃
ps.列表的查询速度比字典快
lis = [1, 2, 3, 4, 5]
a = lis.__iter__()
try:
    a.__next__()
except StopIteration:
    break

 
二,生成器: 顾名思义,生成器就是能够被迭代的,返回一定规格的数据的 特殊函数
  优点:非常节省内存,读取大批量数据时要想到生成器,
  生成器一定是迭代器,迭代器不一定是生成器,是可以让程序员自己制作的迭代器
1.生成器的本质是迭代器,生成器是一个返回迭代器的函数,只能用于迭代操作
2.使用了 yield 的函数被称为生成器(generator),能用__iter__()方法
yield是一种特殊的return
def func():
    print(1)
    a = yield 'a'
# 功能:1.挂起 2.next的返回值 3.接收send的值,没有send的话,默认a=None
    print(2)
    b = yield 'b'
g = func()  # 这里,把生成器func的地址给了变量g,打印g会得到内存地址
print(g.__next__())
generator.send() # 用于向yield传递值,赋值给上面line3的a
# send执行过程包括一次传值和一个next方法,迭代到哪里,就会send到哪里
# 如果生成器还没有执行过next,send参数就只能接收None,因为send先传值,再next
# 在没执行过next时,还没有在yield挂起,也就无法send给任何人,传None之外的
# 东西就会报错
print(g.__next__())
在调用生成器运行的过程中,next()每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
def func():
    li = [1, 2, 3]
    yield from li
g = func()
print(g.__next__())   # 打印1
# yield from 将可迭代对象逐个返回

三,装饰器

开放封闭原则
对扩展开放
对修改源代码封闭
 
作用:为已经存在的对象添加额外的功能
  ps.像一个装饰打包机器,把送进来的对象以一定规格装饰后再打包送出去。即为对象添加特定功能的代码后,再送出去。
 
应用场景:插入日志、性能测试、事务处理、权限校验
def func():
    print('这是原函数。')
 
def wrapper(f):
    def inner():
        pass  # 新功能
        f()
    return inner  # 返回inner的函数指针
func = wrapper(func)  # 现在func这个名字指向inner了
func()  # 执行line5-6
 
@wrapper  # 语法糖,相当于func1 = wrapper(func1)
def func1():
    pass
 
本质是闭包
  外层用于把目标函数(函数名)带进来,即传参,并把完成工作后的内层函数(函数名)返回出去;
  内层用于装饰目标函数。
  经过装饰器修饰之后,目标函数的内存地址就变成了那个内层函数。虽然看起来函数名还是以前的那个,但内在已经变了。
  为了不破坏原函数的逻辑,我们要保证内层函数wrapper和被装饰函数func的传入参数和返回值类型必须保持一致。
 
函数装饰器 @decorator
@wrapper  # 语法糖,相当于func1 = wrapper(func1)
def func1():
    pass
func1()
# 此时,func1已经被wrapper装饰过了 
 
装饰器链
用@进行装饰的顺序:从近到远
def decorator2(f):
   def new():
       print(2)
       return '装饰两次'+f()
   return new
 
def decorator1(f):
   def new():
       print(1)
       return '装饰一次'+f()
   return new
 
@decorator1
@decorator2
def func():
   return "原函数"
 
print(func())
# 输出:
# 1
# 2
# 装饰一次装饰两次原函数
# line11-12等价于以下两行代码
func = decorator2(func)
func = decorator1(func)
 
类方法的函数装饰器
import time
 
def decorator(func):
    def wrapper(me_instance):
        start_time = time.time()
        func(me_instance)
        end_time = time.time()
        print(end_time - start_time)
    return wrapper
 
class Method(object):
 
    @decorator 
    def func(self):
        time.sleep(0.8)
 
p1 = Method()
p1.func() # 函数调用
对于类方法来说,都会有一个默认的参数self,它实际表示的是类的一个实例,所以在装饰器的内部函数wrapper也要传入一个参数me_instance就表示将类的实例p1传给wrapper,其他的用法都和函数装饰器相同。
from functools import wraps
def decorator(func):
    @wraps(func)
# 用于查看原函数的注释

猜你喜欢

转载自www.cnblogs.com/pyonwu/p/10560418.html