• Python中的装饰器,迭代器,生成器


    1. 装饰器

    • 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
    • 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
    • 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
    • 开放封闭原则:对修改封闭,对扩展开放
    import time
    
    def timmer(fun):
        start_time=time.time()
        fun()
        end_time=time.time()
    
    
    def fun1():
        print("in func1")
    
    timmer(fun1)   #改变了原先函数的执行
    
    • 就要用闭包来包装此函数

    import time
    
    def timmer(fun):
        def inner():
            start_time=time.time()
            fun()
            end_time=time.time()
            print("run in {} time {}".format(fun,end_time-start_time))
        return inner   #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用
    
    
    def fun1():
        print("in func1")
    
    print(timmer(fun1))    #可以运行,其实就是执行Inner,目的就是在全局可以调用,
    fun1=timmer(fun1)     #函数本身就是变量,变量值互换
    fun1()                  
    
    • 这样最基本的装饰器就完成了,Python为我们提供了语法糖,一个完整的装饰器如下:会允许函数传参并且返回值不变

    import time
    
    def timmer(fun):
        def inner(*args,**kwargs):
            start_time=time.time()
            ret = fun(*args,**kwargs)
            end_time=time.time()
            print("run in {} time {}".format(fun,end_time-start_time))
            return  ret
        return inner   #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用
    
    @timmer
    def fun1(num):
        print("in func1 {}".format(num))
        return 123
    
    # print(timmer(fun1))    #可以运行,其实就是执行Inner,目的就是在全局可以调用,
    # fun1=timmer(fun1)      #函数本身就是变量,变量值互换
    print(fun1(1))
    
    • 这样可以修饰多个函数,但是要批量更改该怎么,如果不想装饰了,需要挨个去掉吗

    import time
    
    def outer():
        Flag=False
        def timmer(fun):
            def inner(*args,**kwargs):
                if Flag:
                    start_time=time.time()
                    ret = fun(*args,**kwargs)
                    end_time=time.time()
                    print("run in {} time {}".format(fun,end_time-start_time))
                    return ret
                else:
                    ret = fun(*args, **kwargs)
                    return ret
            return inner   #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用
        return timmer   
    
    @outer()           #之所以加执行就是把outer的返回值timmer函数的内存地址放在这里,其实就是@timmer
    def fun1(num):
        print("in func1 {}".format(num))
        return 1
    
    @outer()
    def fun2(num):
        print("in func2 {}".format(num))
        return 2
    
    @outer()
    def fun3(num):
        print("in func3 {}".format(num))
        return 3
    
    print(fun1(1))
    print(fun2(2))
    print(fun3(3))
    
    • 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码

    • 使用小知识点eval

    login_status={"user":None,"status":False}
    
    def outer():
        Flag=True
        def auth(func):
            def inner(*args,**kwargs):
                if Flag:
                    with open("user.txt",encoding="utf-8") as read_f:
                        if login_status['user'] and login_status['status']:
                            ret = func(*args, **kwargs)
                            return ret
                        user_info=eval(read_f.read())
                        name=input("your name>>:").strip()
                        password=input("your password>>:").strip()
                        if name in user_info and user_info[name]["password"] == password:
                            login_status["user"]=name
                            login_status["status"]=True
                            print(login_status)
                            ret = func(*args,**kwargs)
                            return  ret
                        else:
                            print("bad")
                else:
                    ret = func(*args, **kwargs)
                    return ret
            return inner
        return auth
    
    
    @outer()
    def fun1():
        print("in func1")
        return 1
    
    @outer()
    def fun2():
        print("in func2")
        return 2
    
    @outer()
    def fun3():
        print("in func3")
        return 3
    
    fun1()
    fun2()
    fun3()
    
    • 多个装饰器装饰同一个函数

    def wrapper1(func):
        def inner():
            print('wrapper1 ,before func')
            func()
            print('wrapper1 ,after func')
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2 ,before func')
            func()
            print('wrapper2 ,after func')
        return inner
    
    @wrapper2
    @wrapper1
    def f():
        print('in f')
    
    f()
    

      结果原因如下:从后分析

     装饰器小练习:

    #编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
    import time
    from urllib.request import urlopen
    
    def wrapper(func):
        def inner(*args,**kwargs):
            start_time=time.time()
            ret = func(*args,**kwargs).decode('utf-8')
            end_time=time.time()
            print("{} time is {}".format(*args,end_time-start_time))
            return ret
        return inner
    
    @wrapper
    def get(url):
        return urlopen(url).read()
    
    # print(get('http://www.baidu.com'))
    get('http://www.baidu.com')
    

    2. 迭代器

    •  其实迭代就是我们说的,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代

    • 可迭代协议的定义非常简单,就是内部有了__iter__方法。
    from collections import Iterable
    
    l = [1, 2, 3, 4]
    t = (1, 2, 3, 4)
    d = {1: 2, 3: 4}
    s = {1, 2, 3, 4}
    
    print(isinstance(l, Iterable))
    print(isinstance(t, Iterable))
    print(isinstance(d, Iterable))
    print(isinstance(s, Iterable))
    print(dir([1,2]))
    • 用__next__也可以遍历,不依赖for循环

    l=[1,2,3,4]
    l_iter=l.__iter__()          #先把可迭代对象变成迭代器
    print(l_iter.__next__())     #依次取值
    print(l_iter.__next__())     #依次取值
    print(l_iter.__next__())     #依次取值
    print(l_iter.__next__())     #依次取值
    
    • while..try..

    l=[1,2,3,4]
    l_iter=l.__iter__()          #先把可迭代对象变成迭代器
    # print(l_iter.__next__())     #依次取值
    # print(l_iter.__next__())     #依次取值
    # print(l_iter.__next__())     #依次取值
    # print(l_iter.__next__())     #依次取值
    
    
    while True:
        try:
            item = l_iter.__next__()
            print(item)
        except StopIteration:
            break
    

    3. 生成器

    • 一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值

    • 但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。

    • 每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

    • 生成器有什么好处呢?就是不会一下子在内存中生成太多数据

    def genrator_fun1():
        a=1
        yield a
        b=2
        yield b
    
    g=genrator_fun1()
    print(next(g))
    print(next(g))
    #生成器监听文件输入的例子
    

      

      

      

     

      

      

  • 相关阅读:
    android如何从网络中获取数据
    如何写好代码
    如何有效遍历集合中的对象
    Android中自定义控件
    Android如何从网络中获取图片
    如果对象的类型为T1,就做某件事;如果对象的类型为T2,就做另外一件事,请赏自己一个巴掌
    android如何在网络中获取数据
    android shell脚本使用
    ASP.NET应用程序
    php记住用户名和密码实现代码(cookie)
  • 原文地址:https://www.cnblogs.com/so-cool/p/8916225.html
Copyright © 2020-2023  润新知