zoukankan      html  css  js  c++  java
  • python中装饰器之闭包函数(一)

    闭包函数

    '''
    闭包函数:
        1、闭包函数必须在函数内部定义
        2、闭包函数可以引用外层函数的名字
        
        闭包函数是函数对象、函数嵌套、名称空间与作用域的结合体
    '''
    
    
    # 直接传参
    def func(x):
        print(x)
    
    
    # 通过闭包函数传参
    
    def wrapper(x):
        def inner():
            print(x)
    
        return inner
    
    
    func = wrapper(100)  # >>返回inner的内存地址>>>>保存在func中
    func()
    闭包函数定义
    # 闭包函数的应用
    
    import requests
    
    
    # 直接传参
    def spider_func(url):
        response = requests.get(url)
        if response.status_code == 200:
            print(len(response.text))
    
    
    # 闭包函数chuanc
    def spider_outer(url):
        def spider_inner():
            response = requests.get(url)
            if response.status_code == 200:
                print(len(response.text))
    
        return spider_inner
    
    
    url1 = 'https://www.baidu.com/'
    url2 = 'https://www.cnblogs.com/xiaoyuanqujing'
    
    spider_baidu = spider_outer(url1)
    spider_blog = spider_outer(url2)
    spider_baidu()
    spider_blog()
    
    spider_outer(url1)
    闭包函数的应用

     装饰器

    '''
    装饰器
        不修改原函数的源代码
        不修改原函数的调用方式
        
        被装饰对象:即需要添加功能的函数
        装饰器:被装饰函数添加的新功能的函数
    '''

    例子:假设我们现在有一个函数,我们要为其添加一个统计执行时间的功能

    def download_movie():
        print('Start downloading.....')
        time.sleep(3)
        print('Download completed.....')

    讲道理我们是这么执行的

    # 不使用装饰器
    start_time = time.time()
    download_movie()
    stop_time = time.time()
    print(f'Running time is {stop_time - start_time}....')

    问题虽然解决了,但针对每个需要添加统计时间功能的函数,都得敲一遍代码。这显然不符合python所要求的简洁优雅~

    所以我们考虑:

    # 使用装饰器(无返回值时)
    def timer(func):
        def inner():
            start_time = time.time()
            func()  # >>>>>被装饰对象<<<<<
            stop_time = time.time()
            print(f'Running time is {stop_time - start_time}....')
    
        return inner
    
    
    timer(download_movie)  # >>>>>>>>>> 返回inner
    download_movie = timer(download_movie)  # >>>>>>>>>>>以变量名download_movive接收inner
    download_movie()

    问题似乎解决了,然鹅,如果被装饰对象有返回值,如:

    def download_movie():
        print('Start downloading.....')
        time.sleep(3)
        print('Download completed.....')
        return 'Aoi.avi'  # 当被装饰对象有返回值时,上述装饰器需做修改

    我们好像就得不到被装饰对象执行结束后返回的值的,这显然没有什么软用。于是修改装饰器

    def timer(func):
        def inner():
            start_time = time.time()
            res = func()  # >>>>>>>>>>>用res接收func()产生的返回值<<<<<<<<<<<<<<<
            stop_time = time.time()
            print(f'Running time is {stop_time - start_time}....')
            return res  # 返回>>>>>>>>>>res<<<<<<<<<< (本例子中即download_movie的返回值)
    
        return inner
    
    
    download_movie = timer(download_movie)
    print(download_movie())  # >>> Aoi.avi

    问题好像又解决了,然鹅,如果被装饰对象有参数,如:

    # 使用装饰器(被装饰对象有参数)
    def download_movie(url):
        print(f'From {url}
    Start downloading........')
        time.sleep(3)
        print(f'Download completed')
    
    如果还是 download_movie = timer(download_movie)
    download_movie(url) >>>>>># 会报错,因为download实际上是inner的别名。调用的是inner(url)

    于是修改装饰器:

    def timer(func):
        def inner(url):
            start_time = time.time()
            func(url)  # 从闭包函数inner获取参数
            stop_time = time.time()
            print(f'Running time is {stop_time - start_time}....')
    
        return inner
    
    
    download_movie = timer(download_movie)  # >>>>>返回inner >>>>>>更名为download_movie
    download_movie('https://www.baidu.com/')

    问题好像又解决了,然鹅,如果不确定被装饰对象的参数个数那又该怎么办呢?

    修改装饰器,最终版本:

    def timer(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)  # >>>>>>>>>>>用res接收func()产生的返回值<<<<<<<<<<<<<<<
            stop_time = time.time()
            print(f'Running time is {stop_time - start_time}....')
            return res  # 返回>>>>>>>>>>res<<<<<<<<<< (本例子中即download_movie的返回值)
    
        return inner

    解决~~~~

     欸,等下~~~~~~~~~~~这装饰器用起来还是有点麻烦啊

    python大佬为我们提供了更简洁的装饰器调用方式。装饰器语法糖@

    def timer(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)  # >>>>>>>>>>>用res接收func()产生的返回值<<<<<<<<<<<<<<<
            stop_time = time.time()
            print(f'Running time is {stop_time - start_time}....')
            return res  # 返回>>>>>>>>>>res<<<<<<<<<< (本例子中即download_movie的返回值)
    
        return inner
    
    
    @timer
    def func():
        print('hello world')
    
    
    # 当我们调用func()时
    func()
    # 等价于  func = timer(func)  func()
  • 相关阅读:
    剑指offer 44.知识迁移能力 翻转单词顺序列
    Spark Streaming 概述+DStream工作原理+与Storm对比+实时WordCount
    剑指offer 43.知识迁移能力 左旋转字符串
    剑指offer 42.知识迁移能力 和为S的两个数字
    剑指offer 41.知识迁移能力 和为S的连续正数序列
    剑指offer 40.知识迁移能力 数组中只出现一次的数字
    Spark 在yarn上运行模式详解:cluster模式和client模式
    10.25模拟赛
    线段树+Dfs序【p2982】[USACO10FEB]慢下来Slowing down
    线段树 (区间合并)【p2894】[USACO08FEB]酒店Hotel
  • 原文地址:https://www.cnblogs.com/Ghostant/p/11841314.html
Copyright © 2011-2022 走看看