装饰器 迭代器 生成器(yield 与return的异同)

方案五:

import time

def index():   # index=被装饰对象index函数的内存地址
    time.sleep(1)
    print("from index")

def foo(func):        # func=被装饰对象index函数的内存地址
    def wrapper():
        start = time.time()
        func()         # func=被装饰对象index函数的内存地址
        stop = time.time()
        print("run time is %s" % (stop - start))
    return wrapper  # 丢出来wrapper的是wrapper的函数内存地址,定义阶段不可以加括号

index = foo(index)   # foo()这个时候就等于wrapper
print(index)      # 这时候index就是wrapper,已经不是上面的index了
index()

方案六:将wrapper伪装成被装饰的函数,那么应该装的尽可能像一点

import time

def index(x,y,z):
    time.sleep(1)
    print("from index",x,y,z)

def home(name):
    time.sleep(2)
    print("welcome %s to home page"% name)
    return 123

def foo(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print("run time is %s" % (stop - start))
        return res
    return wrapper

index = foo(index)
index(1,2,3)
home = foo(home)
res = home("nana")
print(res)

注意小点:
我们在运行完一个函数代码后,如果事先定义好了return返回值。那么在函数代码运行结束后,函数的返回值是一定会被丢出来的。
丢出来的返回值跟变量值一样,直接添加一个变量名,通过print就可以直接看到了。

无参装饰器的模板

def outter(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper
    

装饰器语法糖

方案六:将wrapper伪装成被装饰的函数,那么应该装的尽可能像一点
import time
from functools import wraps      
# 这个是python自带写好的装饰器,导入wraps的模块,会把func自带所有的属性全部覆盖给wrapper(加不加都可以)

def foo(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print("run time is %s" % (stop - start))
        return res
    return wrapper

@foo    # index = foo(index)  # foo(被装饰对象index函数的内存地址)-->返回wrapper函数的内存地址-->index = wrapper
def index():
    """...这是index内存地址..."""
    time.sleep(1)
    print("from index")

@foo     # home = foo(home)	= wrapper,home(name) = wrapper(name),调用的时候,实际上是直接从foo()函数的接口调用
def home(name):
    time.sleep(2)
    print("welcome %s to home page"% name)
    return 123

res = home("nana")
print(res)

res = index()
print(res)

print(index.__name__)	
print(index.__doc__)

登陆认证装饰器

def outter(func):
    def wrapper(*args, **kwargs):
        name = input("username:").strip()
        pwd = input("password:").strip()
        if name == "nana" and pwd == "123":
            res = func(*args, **kwargs)
            return res
        else :
            print("账号密码错误")

    return wrapper

@outter
def index():
    print("index")

index()  # index = outter(index)

叠加多个装饰器

def doco1(func1):      # func1 = wrapper2的内存地址
    def wrapper1(*args, **kwargs):
        print("===========wrapper1")
        res1 = func1(*args, **kwargs)
        print("end1")
        return res1
    return wrapper1

def doco2(func2):       # func2 = wrapper3的内存地址
    def wrapper2(*args, **kwargs):
        print("===========wrapper2")
        res2 = func2(*args, **kwargs)
        print("end2")
        return res2
    return wrapper2

def doco3(func3):         # func3 = 被装饰的index的内存地址
    def wrapper3(*args, **kwargs):
        print("============wrapper3")
        res3 = func3(*args, **kwargs)
        print("end3")
        return res3
    return wrapper3

                                      index = wrapper1的内存地址
@deco1      # deco1  (wrapper2的内存地址)->wrapper1的内存地址
@deco2      # deco2  (被装饰wrapper3的内存地址)->wrapper2的内存地址
@deco3      # dexo3  (被装饰的index的内存地址)->wrapper3的内存地址
def index():
    print("index...")

index()

运行是自上而下运行,先运行wrapper1,在运行wrapper2,在运行wrapper3,最后运行index。
返回值是自下而上的,先打印end3,再end2,最后end1。
最后的运行结果:
===========wrapper1
===========wrapper2
============wrapper3
index...
end3
end2
end1

装饰器只需要看最内层的函数体代码就可以了,多个装饰器嵌套执行顺序从上到下
装饰器只需要看最内层的函数体代码就可以了,多个装饰器嵌套执行顺序从上到下
装饰器只需要看最内层的函数体代码就可以了,多个装饰器嵌套执行顺序从上到下

上面例子的具体原理图可以看下图
在这里插入图片描述

迭代器
什么是迭代器?
迭代器:迭代取值的工具。
什么是迭代:迭代的基础是重复,但是每次重复都是在上一次基础上进行的。

nums = [111,222,333]
nums = "hello"
def get(l):
    i = 0
    while i < len(l):
        print(l[i])
        i += 1
get(nums)

为何要使用迭代器?
迭代器提供了一种不依赖于索引的通用的可以取值的方法。
节省内存。
如何使用迭代器?

可迭代对象:含有__iter__方法的对象。

当可迭代对象调用__iter__方法的时候,返回一个迭代器对象。
我们所学习的数据类型中,有很多数据类型都有内置的__iter__方法
字符串,列表,元组,字典,集合文件都有python解释器内置的iter方法,而文件不止有iter方法,还有next方法。

a = ""
a.__iter__()
b = []
b.__iter__()
c = ()
c.__iter__()
d = {}
d.__iter__()
f = open("a.txt",mode="wt")  # 文件对象本就是迭代器对象
f.__iter__()
f.__next__()

迭代器对象:含有__iter__和__next__方法的对象。

当迭代器对象调用__iter__方法的时候,返回的是它自己。
当迭代器对象调用__next__方法的时候,拿到的是下一个值。
可以一直使用__next__方法取下一个值,直到抛出异常StopIteration。

nums = [1, 2, 3]
nums_iter = nums.__iter__()
print(nums)
print(nums_iter)
print(nums_iter.__next__())
print(nums_iter.__next__())
print(nums_iter.__next__())
print(nums_iter.__next__())    # 调完显示StopIteration

x = iter(nums)           # 将可迭代对像nums调用iter方法,返回了一个迭代器对象x
print(next(x))
print(next(x))
print(next(x))

for循环原理:

for循环原理代码演示:
nums = [1, 2, 3]
nums_iter = iter(nums)  	# 将可迭代对象nums转成迭代器对象

while True:
    try:
        res = next(nums_iter)
        print(res)
    except StopIteration:  # 捕捉异常结束
        break

先调用in后那个对象_iter_方法,拿到迭代器对象
res = next(迭代器对象),执行一次循环体代码
循环往复步骤2:直到值取干净抛出异常StopIteration,for循环会捕捉到异常后结束循环
for res in nums:
    print(res)
        

生成器

当函数内出现yield关键字,再调用函数并不会触发函数体代码的运行,会返回一个生成器
生成器就是一种自定义的迭代器,
yield可以将函数暂停住,next一次,会运行一次,当一个函数里面所有的yield全部取值干净了,会返回异常StopIteration

yield 与return的异同
相同点:返回值层面用法一样
不同点:return只能返回值一次,而yield的返回值可以返回多次

def func():
    print("xxx")
    yield 111
    print("yyy")
    yield 222
    print("zzz")

func()	# 没有任何打印结果
g = func()		# g就是func函数的生成器
print(g)	# <generator object func at 0x01735220>

res = next(g)		# 打印xxx,返回值111赋值给res
print(res)			# 111

res = next(g)			# 打印yyy,返回值222赋值给res
print(res)			# 222

next(g)			# 打印zzz,抛出异常StopIteration

当函数内出现yield关键字,再调用函数并不会触发函数体代码的运行,会返回一个生成器
生成器就是一种自定义的迭代器,yield可以将函数暂停住,next一次,会运行一次,当一个函数里面所有的yield全部取值干净了,会返回异常StopIteration
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值