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

    闭包函数

    什么是闭包函数

    闭包函数把 闭包函数内的变量 + 闭包函数内部的函数, 这两者包裹起来,然后通过返回值的形式返回出来。

    • 定义在函数的内函数
    • 该函数体代码包含对该函数外层作用域中变量的引用
    • 函数外层指的不是全局作用域
    def outter():
        x = 10
        def inner():
            print(x)
        return inner
    
    f = outter()  # f=inner
    f()
    print(f)
    
    # 打印结果:
    10
    <function outter.<locals>.inner at 0x00000201011A7840>
    

    上述代码中,f是一个全局的名字,但f拿到了inner的内存地址。将一个定义在内部的函数返回出来,在全局拿到f,这个f是全局变量,这样就打破了函数的层级限制,能在任意位置使用内部的函数

    闭包函数的应用

    以参数的方式传值

    import requests
    
    def get(url):
        response = requests.get(url)
        print(response.text)
    
    get('https://www.baidu.com')
    

    这里写了一个爬虫函数,爬取百度的首页。但这样的问题就是每次想爬百度,或者其他网站都要传一堆网址,比较麻烦,所以可以用闭包函数解决。

    传值另一方式: 包给函数

    import requests
    
    def spider(url):
        def get():
            response = requests.get(url)
            print(response.text)
        return get
    
    baidu = spider('https://www.baidu.com')
    baidu()
    
    taobao = spider('https://www.taobao.com')
    taobao()
    

    这样就很方便,以后调baidu,直接baidu()就行了

    装饰器

    什么是装饰器

    装饰器就是 为需要装饰的函数新增了一个额外的功能,装饰器的本质就是一个 给函数增加功能的函数。

    为什么要装饰器

    装饰器,增加功能需要注意以下几点:

    • 不改变原函数的原代码
    • 不改变原函数的调用方式

    使用无参装饰器

    import time
    
    def index():
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
    
    index()
    

    需要为上面的函数新增加一个功能,能够统计函数运行的时间

    在原代码上修改

    import time
    
    def index():
        start = time.time()
        time.sleep(1)
        print('welcome to index')
        end = time.time()
        print(f'run time is {end - start}')
    
    index()
    

    这样就违反了不能修改原代码这一原则

    import time
    
    def index():
        time.sleep(1)
        print('welcome to index')
    
    start = time.time()
    index()
    end = time.time()
    print(f'run time is {end - start}')
    
    

    这样写就不是装饰器,因为装饰器是一个函数

    利用函数传参方式

    import time
    
    def index():
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
    
    def time_count(func):
        start = time.time()
        func()
        end = time.time()
        print(f'run time is {end - start}')
    
    time_count(index)
    
    

    虽然实现了,但改变了函数调用方式

    利用闭包

    import time
    
    def index():
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
    
    def deco(func):  # func = index 最初的index
        def time_count():
            start = time.time()
            func()
            end = time.time()
            print(f'run time is {end - start}')
        return time_count
    
    # f = deco(index)   
    
    index = deco(index)   # index = time_count
    index()
    

    这样就简单实现了一个装饰器函数,调用index不是调用最初的index了,而是调用time_count函数,但用户不知道,看起来就和原来使用一样

    装饰器完善

    上述的装饰器,最后调用index()的时候,其实是在调用time_count(),因此如果原始的index()有返回值的时候,time_count()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和time_count()方法的返回值。

    import time
    
    def index():
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
        return 1234
    
    def deco(func):
        def time_count():
            start = time.time()
            res = func()
            end = time.time()
            print(f'run time is {end - start}')
            return res
    
        return time_count
    
    # index = deco(index)   # index = time_count
    # index()
    res = index()
    print(res)
    

    给原始index传参

    import time
    
    def index(x):
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
        return 1234
    
    def deco(func):
        def time_count(*args,**kwargs):
            start = time.time()
            res = func(*args,**kwargs)
            end = time.time()
            print(f'run time is {end - start}')
            return res
    
        return time_count
    
    index = deco(index)   # index = time_count
    index(10)
    
    

    使用装饰器语法糖

    import time
    
    
    def deco(func):
        def time_count(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print(f'run time is {end - start}')
            return res
    
        return time_count
    
    
    @deco    # 这里就相当于 index = deco(index)
    def index(x):
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
        return 1234
    
    
    index(10)
    

    装饰器模板

    def deco(func):
        def wrapper(*args,**kwargs):
            # 这里加功能
            res = func(*args,**kwargs)
            return res
        
        return wrapper
    

    装饰器小练习

    # 写一个登录装饰器,装饰猜年龄,登录了才能玩猜年龄
    
    username_list = []
    
    def guess(age):
        print('welcome to guess age')
        age_inp = input('请猜年龄').strip()
        age_inp = int(age_inp)
    
        if age_inp == age:
            print('bingo')
        elif age_inp < age:
            print('猜小了')
        else:
            print('猜大了')
    
    
    def login(func):
        def wrapper(*args,**kwargs):
            if username_list:
                print('已登录,请勿重复登录')
                res = func(*args, **kwargs)
                return res
    
            username_inp = input('请输入用户名:').strip()
            pwd_inp = input('请输入密码:').strip()
    
            with open('user_info.txt', 'r', encoding='utf-8') as fr:
                for user_info in fr:
                    user_info = user_info.strip()
                    username, pwd = user_info.split(':')
    
                    if username_inp == username and pwd_inp == pwd:
                        print('登录成功')
                        username_list.append(username_inp)
                        res = func(*args, **kwargs)
                        return res
    
                    else:
                        print('登录失败')
    
            res = func(*args,**kwargs)
            return res
    
        return wrapper
    
    guess = login(guess)
    guess(19)
    

    有参装饰器

    import time
    
    def outter(age):
        def deco(func):
            def wrapper(*args,**kwargs):
                if age >= 18:
                    print('成年了')
                else:
                    print('未成年')
    
                start = time.time()
                res = func(*args,**kwargs)
                end = time.time()
                print(f'run time is {end - start}')
                return res
    
            return wrapper
    
        return deco
    
    @outter(19)  #   相当于 deco = outter(19)   index = deco(index)
    def index():
        '''被装饰函数'''
        time.sleep(1)
        print('welcome to index')
    
    index()
    
  • 相关阅读:
    win8 连接到OneDrive时出现问题-感叹号
    让tp6显示详细的错误信息及行号
    TP6出现错误 No input file specified.
    Git 访问慢 解决办法
    mysql5.7当两个字段名类似,查询时会出错
    linux停止进程
    mysql更新数据时:当想mysql某插入有某字段设置了unique且和之前相同时,会报错,并停止运行
    php升级版本后的影响5.5->7.1


  • 原文地址:https://www.cnblogs.com/setcreed/p/11575123.html
Copyright © 2011-2022 走看看