zoukankan      html  css  js  c++  java
  • python基础语法7 闭包函数与装饰器

    闭包函数:

    定义:

      1 定义再函数内部

      2 对外部作用域有引用

    闭包函数是 函数嵌套、函数对象、名称空间与作用域 结合体。

    创建闭包必须满足以下3点: 
    1. 闭包函数必须有内嵌函数
    2. 内嵌函数需要引用该嵌套函数上一级变量
    3. 闭包函数必须返回内嵌函数
    # 直接传参
    def func(x):
        print(x)
    
    func(1000)
    
    
    # 通过闭包函数传参
    def outer(number):
        # number = 100
        # inner就是闭包函数
        def inner():
            print(number)
        return inner
    
    func = outer(1000)  # ---》 inner地址 ---》 func变量名
    func()  # func ---> inner地址()

    闭包函数的应用

    # 方式一: 直接传参
    def spider_func(url):
        # 往url地址发送请求,获取响应数据
        response = requests.get(url)  # 必须接受url
        # 状态码: 200
        if response.status_code == 200:
            # 获取当前url地址中所有的文本
            print(len(response.text))
            print(response.text)
    url = 'https://www.cnblogs.com/xiaoyuanqujing/'
    spider_func(url)
    ——————————————————————————
    # 方式二: 通过闭包函数接受url地址,执行爬取函数
    def spider_outer(url):
        # url = 'https://www.cnblogs.com/xiaoyuanqujing/'
        def spider_inner():
            response = requests.get(url)
            if response.status_code == 200:
                print(len(response.text))
        return spider_inner
    
    
    # 爬取 小猿取经
    spider_blog = spider_outer('https://www.cnblogs.com/xiaoyuanqujing/')
    spider_blog()
    # 爬取 京东
    spider_baidu = spider_outer('https://www.baidu.com/')
    spider_baidu()

    装饰器:

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

      被装饰对象: ---> 需要添加功能 函数
      装饰器: ---> 被装饰对象添加的新功能的 函数

      time_record ---》 装饰器

    需求: 统计下载电影函数的运行时间。

    # 下载电影功能(初始代码)
    def download_movie():
        print('开始下载电影...')
        # 模拟电影下载时间 3秒
        time.sleep(3)  # 等待3秒
        print('电影下载成功...')
        return 'sean与jason的雨后的小故事.mp4'
    
    
    start_time = time.time()  # 获取当前时间戳
    download_movie()
    end_time = time.time()  # 获取当前时间戳
    print(f'消耗时间: {end_time - start_time}')
    # 问题: 多个被装饰对象,需要写多次统计时间的代码,导致代码冗余。
    # 装饰器: 初级版
    def time_record(func):
        def inner(*args, **kwargs):
            # 统计开始
            start_time = time.time()
    
            # 被装饰对象, 问题1: 有返回值, 问题2: 不确定参数的 个数
            res = func(*args, **kwargs)  # func() ---> download_movie()
            # 当被统计的函数执行完毕后,获取当前时间
            end_time = time.time()
            # 统计结束,打印统计时间
            print(f'消耗时间: {end_time - start_time}')
    
            return res
    
        return inner
    
    
    download_movie = time_record(download_movie)  # inner
    # name = 'egon'
    # download_movie(name)
    download_movie(name='egon')
    
    
    
    # inner()  #  inner() ---> download_movie()
    
    # download_movie = time_record(download_movie)  # inner
    
    
    
    # download_movie()  #  download_movie() ---> download_movie()
    # 问题1: 被装饰对象 有返回值
    
    
    # 下载电影功能
    def download_movie():
        print('开始下载电影...')
        # 模拟电影下载时间 3秒
        time.sleep(3)  # 等待3秒
        print('电影下载成功...')
        return '小泽.mp4'
    
    
    def time_record(func):  # func <-- download_movie
    
        # 在闭包函数中
        def inner():
            # 统计开始
            start_time = time.time()
            res = func()  # func() ---> download_movie()
            # 当被统计的函数执行完毕后,获取当前时间
            end_time = time.time()
            # 统计结束,打印统计时间
            print(f'消耗时间: {end_time - start_time}')
    
            return res
    
        return inner
    
    
    download_movie = time_record(download_movie)
    download_movie()
    #问题2: 被装饰对象 有参数
    #下载电影功能
    import time
    def download_movie(url):
        print(f'{url}中的电影开始下载了...')
        # 模拟电影下载时间 3秒
        time.sleep(3)  # 等待3秒
        print('电影下载成功...')
        return '小泽.mp4'
    
    
    def time_record(func):  # func <-- download_movie
        # url = 'https://www.baidu.com/'
    
        # 在闭包函数中
        def inner(url):
            # 统计开始
            start_time = time.time()
    
            res = func(url)  # func(url) ---> download_movie(url)
    
            # 当被统计的函数执行完毕后,获取当前时间
            end_time = time.time()
            # 统计结束,打印统计时间
            print(f'消耗时间: {end_time - start_time}')
            return res
        return inner
    
    download_movie = time_record(download_movie)
    
    download_movie(url) --> inner(url)
    download_movie('https://www.baidu.com')
    #问题4: 假如被装饰对象需要接收多个参数
    def download_movie(url, url2, url3):
        print(f'{url}中的电影开始下载了...')
        # 模拟电影下载时间 3秒
        time.sleep(3)  # 等待3秒
        print('电影下载成功...')
        return '小泽.mp4'
    
    def download_movie():
        print('电影开始下载...')
        # 模拟电影下载时间 3秒
        time.sleep(3)  # 等待3秒
        print('电影下载成功...')
        return '小泽.mp4'
    # 装饰器最终版本
    def time_record(func):  # func <-- download_movie
        # 在闭包函数中
        def inner(*args, **kwargs):  # *args, **kwargs接收所有参数
    
            # 统计开始
            start_time = time.time()
    
            # 将被装饰对象需要接收的任意参数 原封不动传给func --》 被装饰对象
            res = func(*args, **kwargs)  # func(url) ---> download_movie(url)
    
            # 当被统计的函数执行完毕后,获取当前时间
            end_time = time.time()
            # 统计结束,打印统计时间
            print(f'消耗时间: {end_time - start_time}')
    
            return res
        return inner
    
    # download_movie = time_record(download_movie)
    #
    # download_movie()
    # download_movie(url) --> inner(url, url2, url3)
    # download_movie(url1='https://www.baidu.com', url2='url2', url3='url3')
    # 装饰器模板:权限设定
    # 装饰器最终版本
    def wrapper(func):
    
        def inner(*args, **kwargs):
    
            # 让用户输入内容
            username = input('请输入名字')
    
            if username == 'tank':
                # 调用被装饰对象,得到返回值
                res = func(*args, **kwargs)
                return res
    
            else:
                print('用户权限不足!')
    
        return inner
    
    def func1():
        pass
    
    func1 = wrapper(func1)
    func1()  # inner()

    装饰器的语法糖,是属于装饰器的。
    @: 装饰器的语法糖

    # 注意: 在使用装饰器语法糖时,装饰器必须定义在被装饰对象之上

    import time
    
    # 统计函数执行时间装饰器
    def wrapper(func):  # 被装饰对象
        def inner(*args, **kwargs):  # 被装饰对象的参数
            # 调用前增加新功能
            start_time = time.time()
            # 调用被装饰对象,并接收返回值
            res = func(*args, **kwargs)
    
            # 调用后添加新功能
            end_time = time.time()
            print(end_time - start_time)
    
            return res
        return inner
    
    # func函数需要执行3秒
    
    # 无参装饰器
    # 使用装饰器
    @wrapper  # wrapper(func)  ---> func
    def func():
    
        time.sleep(3)
    
    func()
  • 相关阅读:
    C++对象模型
    Session、Application、Cache
    JavaScript事件的几个细节
    algorithm(算法)
    【REST WCF】30分钟理论到实践
    实践Scrum
    调试PostSharp DEMO 遇到的问题
    6.8 按字符串中的部分内容排序
    QObject就有eventFilter,功能很强(随心所欲的进行处理,比如用来QLineEdit分词)
    QPainter就是手里的作图工具,只需要三洋东西:笔(颜色,宽度,样式),字体(写字),刷子(大面积作画),这里有三个典型例子
  • 原文地址:https://www.cnblogs.com/ludingchao/p/11844921.html
Copyright © 2011-2022 走看看