zoukankan      html  css  js  c++  java
  • 闭包函数与装饰器

    闭包函数

    什么是闭包

    闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。

    def outter():
        x = 1
    
        def inner():
            print(x)  # x = 1
        return inner
    
    
    f = outter()  # f = inner
    
    
    def f2():
        x = 2
        f()  # f() = inner()
    
    
    f2()
    
    1
    

    两种为函数传参的方式

    方式一:使用参数的形式

    def func(x):
        print(x)
    
    
    func(1)
    
    1
    

    方式二:包给函数

    def outter(x):
    
        def inner():
            print(x)
        return inner
    
    
    f = outter(1)  # f = inner  ,x = 1
    
    print(f)
    f()
    
    <function outter.<locals>.inner at 0x0000017E2A641048>
    1
    

    闭包函数的应用

    闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

    应用领域:延迟计算(原来我们是传参,现在我们是包起来)、爬虫领域。

    import requests
    
    
    def outter(url):
        def get():
            respond = requests.get(url)
            print(f'done:{url}')
        return get
    
    
    baidu = outter('http://www.baidu.com')  # baidu = get
    
    baidu()  # baidu() = get()
    
    taobao = outter('http://www.taobao.com')  # taobao = get
    
    taobao()
    
    done:http://www.baidu.com
    done:http://www.taobao.com
    

    装饰器

    无参装饰器

    什么是装饰器

    器指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器对象添加额外功能。

    注意:

    • 装饰器本身其实是可以任意调用的对象
    • 被装饰的对象也可以是任意可调用的对象

    为什么要用装饰器

    如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方发法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能是开放的。

    装饰器的实现必须遵循两大原则:

    1. 不修改被装饰对象的源代码
    2. 不修改被装饰对象的调用方式

    装饰器就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

    怎么用装饰器

    # 改变调用方式
    
    import time
    
    
    def index():
        print('welcome to index')
        time.sleep(1)
    
    
    def time_count(func):
        start = time.time()
        func()   # index()
        end = time.time()
        print(f'{func} time is {end - start}')
    
    
    time_count(index)   # 改变了index的调用方式
    
    welcome to index
    <function index at 0x0000017E2A84BD90> time is 1.0003917217254639
    
    # 包给函数—外包
    
    import time
    
    
    def index():
        print('welcome to index')
        time.sleep(1)
    
    
    def time_count(func):
    
        def wrapper():
            start = time.time()
            func()  # index()
            end = time.time()
            print(f'{func} time is {end - start}')
        return wrapper
    
    
    print(index)  # <function index at 0x0000017E2A781B70>
    print('*'*20)
    index = time_count(index)  # index = wrapper
    index()  # index() = wrapper()
    print('*'*20)
    print(index)  # 地址与第一个打印不同
    # <function time_count.<locals>.wrapper at 0x0000017E2A8A00D0>
    
    <function index at 0x0000017E2A781B70>
    ********************
    welcome to index
    <function index at 0x0000017E2A781B70> time is 1.0003859996795654
    ********************
    <function time_count.<locals>.wrapper at 0x0000017E2A8A00D0>
    

    完善装饰器

    1. 如果原始的index()有调用值,上述的wrapper()却没有,两者的返回值应该相同,我们需要同步原始函数有个返回值。
    import time
    
    
    def index():
        print('welcome to index')
        time.sleep(1)
        return "I'm index"
    
    
    def time_count(func):
        
        def wrapper():
            start = time.time()
            res = func()  # res = index() = "I'm index"
            end = time.time()
            print(f'{func} time is {end - start}')
            
            return res
        return wrapper
    
    print(index())
    print('*'*20)
    index = time_count(index)
    res = index()
    print(res)
    
    welcome to index
    I'm index
    ********************
    welcome to index
    <function index at 0x0000017E2A8858C8> time is 1.0053789615631104
    I'm index
    
    1. 如果原始的函数需要传参,那么我们之前的装饰器无法实现该功能的,那么只要给wrapper()传参即可。
    import time 
    
    def home(name):
        print(f'welcome {name} to home page')
        time.sleep(1)
        
        return name
        
    def time_count(func):
        
        def wrapper(*args,**kwargs):
            
            start = time.time()
            res = func(*args,**kwargs)
            end = time.time()
            print(f'{func} time is {end - start}')
            
            return res
        return wrapper
    
    
    home = time_count(home)  # home = wrapper
    res = home('william')  res = wrapper('william')
    print(res)
    
    welcome william to home page
    <function home at 0x0000017E2A8856A8> time is 1.0003857612609863
    william
    

    装饰器语法糖

    在被装饰的函数上方,单独写一行@装饰器名

    # 上方函数用语法糖
    import time 
    
    def time_count(func):
        
        def wrapper(*args,**kwargs):
            
            start = time.time()
            res = func(*args,**kwargs)
            end = time.time()
            print(f'{func} time is {end - start}')
            
            return res
        return wrapper
    
    @time_count
    def home(name):
        print(f'welcome {name} to home page')
        time.sleep(1)
        
        return name
    
    @time_count
    def index():
        print('welcome to index')
        time.sleep(1)
        return "I'm index"
        
    
        
    print(index())
    print('*'*20)
    print(home('william'))
    
    welcome to index
    <function index at 0x0000017E2A885E18> time is 1.0003869533538818
    I'm index
    ********************
    welcome william to home page
    <function home at 0x0000017E2A885D90> time is 1.0013864040374756
    william
    

    装饰器模板

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

    有参装饰器

    无参装饰器只套了两层,下面是三层装饰器—有参装饰器。这个参数是装饰器的参数。

    # 登陆注册(判断信息来源,'file'可以,其他不行)
    
    is_login_dict = {'username':None}
    
    def auth(origin):
        
        def login(func):
            
            def wrapper(*args,**kwargs):
                
                if origin == 'file':
                    print('from file')
                    
                    if not is_login_dict.get('username'):
                        username = input('please enter your username>>>').strip()
                        print('login successfully')
                        res = func(*args,**kwargs)
                        is_login_dict['username'] = username
                        return res
                    else:
                        res = func(*args,**kwargs)
                        return res
                else:
                    
                    print('illegal original')
            return wrapper
        return login
    
    
    @auth('file')
    def shopping(): 
        print('from shopping')
    
        
    @auth('mongodb')
    def withdraw():
        print('from withdraw')
        
    @auth('file')
    def paying():
        print('from paying')
        
        
        
    shopping()   # 需要输入用户名
    print('*'*20)
    withdraw()   #来源错误
    print('*'*20)
    paying()    # 无需再次输入用户名
    
    from file
    please enter your username>>>william
    login successfully
    from shopping
    ********************
    illegal original
    ********************
    from file
    from paying
    
  • 相关阅读:
    Java学习笔记8(面向对象3:接口)
    面向对象2(继承,抽象类)
    java学习笔记6(面向对象1:概念,private)
    排序方法-循环和数组练习
    ArrayList方法综合练习
    Eclipse的配置
    集合(ArrayList)简述
    java学习笔记5(方法)
    数据结构9——最小生成树
    数据结构8——图的遍历
  • 原文地址:https://www.cnblogs.com/WilliamKong94/p/10961928.html
Copyright © 2011-2022 走看看