第12天 装饰器 迭代器

方案五:

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,**wkargs):
        start = time.time()
        res = func(*args, **wkargs)
        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就可以直接看到了。

装饰器语法糖:

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

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

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

@foo     #home = foo(home)
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,**wkargs):
        res=func(*args,**kwargs)
        return res
    return wrapper
    

登陆认证装饰器

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)

为何要用迭代器
1.迭代器提供了一种不依赖于索引的,通用的取值方案
2.节省内存

如何用迭代器
可迭代的对象
1.内置有_iter_方法的都叫可迭代的对象
调用可迭代对象_iter_方法,返回的是它的迭代器
迭代器对象
1.内置有_next_方法
2.内置有_iter_方法
调用可迭代对象_iter_方法,得到的是它自己,就跟没调一样
调用迭代器_next_的方法返回的下一个值,不依赖索引
可以一直调用_next_直到取干净,则抛出异常StopIteration
迭代器对象包含了可迭代对象

内置的类型都是可迭代的对象

扫描二维码关注公众号,回复: 12529986 查看本文章
"abc"
[1, 2, 3]
(1, 2, 3)
{
    
    "k1": 111}
{
    
    1, 2, 3}

f=open("a.txt",mode="wt")   #文件对象本身都是迭代器对象

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,x就变成了nums的迭代器
print(next(x))
print(next(x))
print(next(x))

for循环原理:

nums=[1,2,3]

nums=iter(nums)                  #将可迭代对象nums转成迭代器对象
    try:
        res = next(nums_iter)
        print(res)
    except StopIteration:        # 捕捉异常结束
        break


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

yield 与return的异同

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

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

g = func()

res=next(g)
print(res)

next(g)
next(g)
next(g)
next(g)

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

猜你喜欢

转载自blog.csdn.net/Yosigo_/article/details/111993544