• 函数进阶(1)


    1 闭包函数

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

    闭包函数:传参的另外一种方式,参数+函数包在一起传出去

    1.1 函数传参方式

    # 函数传参的方式一:使用参数
    def inner(x):
        print(x)
    
    inner(1)
    inner(1)
    inner(1)
    
    # 函数的传参方式二:闭包函数,把变量和函数一起包起来,下次要用直接调用
    def outter(x):
        def inner():
            print(x)
        return inner
    inner = outter(2) # inner # f = inner
    inner()
    inner()
    inner()
    

    1.2 闭包函数的应用

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

    import requests
    
    def get_res(url):
        res = requests.get(url)
        print(res.txt)
    
    get_res('https://www.baidu.com/')
    get_res('https://www.baidu.com/')
    get_res('https://www.baidu.com/')
    
    get_res('https://www.taobao.com')
    get_res('https://www.taobao.com')
    get_res('https://www.taobao.com')
    
    get_res('https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-links-3.20.5af911d9iW0QkW')
    get_res('https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-links-3.20.5af911d9iW0QkW')
    get_res('https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-links-3.20.5af911d9iW0QkW')
    
    上面的方式极其复杂,我们如果使用默认参数也只能解决一个网址,因此我们可以考虑使用闭包的方式。
    import requests
    def func(url):
        def get_res():
            res = requests.get(url)
            print(res.text)
        return get_res
    baidu_spider = func('https://www.baidu.com/')
    baidu_spider()
    baidu_spider()
    
    taobao_spider = func('https://www.taobao.com')
    taobao_spider()
    taobao_spider()
    

    2 装饰器

    2.1 装饰器的定义

    装饰器:装饰的工具(函数),这个函数有装饰的作用

    装饰器本质就是一个函数A,装饰的对象也是一个函数B,用一个函数A去装饰一个函数B

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

    ​ 1.不改变函数B的调用方式

    ​ 2.不改变函数B的源代码

    def A():
        """装饰器"""
        pass
    
    def B():
        """被装饰的对象"""
        pass
    
    B()
    

    2.2 装饰器的使用

    def index():
        """被装饰的函数"""
        print('hello,index')
    
    index()
    
    # 打印函数运行的时间
    
    # 1.改变函数体代码,没改变调用方式
    import time
    
    def index():
        start = time.time()
        print('hello,index')
        time.sleep(1)
        end = time.time()
        print(end - start)
    
    index()
    
    # 2没改变调用方式,也没改变源码,但是不通用
    import time
    def index():
        """被装饰的函数"""
        print('hello,index')
    
    def index1():
        print('hello,index')
    
    start = time.time()
    index1()
    time.sleep(1)
    end = time.time()
    print(end - start)
    
    # 装饰器
    # 检测index的运行的时间,但是不能改变index的调用方式,以及index的源码
    import time
    
    def deco(func): # func = index
        """装饰器函数"""
        def inner():
            start = time.time()
            func() # index
            time.sleep(1)
            end = time.time()
            print(end - start)
        return inner
    
    def index():
        """被装饰的函数"""
        print('hello,index')
    
    def index1():
        print('hello,index1')
    
    index = deco(index) # index = inner
    index()
    

    2.3 装饰器语法糖

    在被装饰函数正上方,并且是单独一行写上@装饰器名

    import time
    
    def deco(func):
        def f1(*args,**kwargs):
            print('args:',args) # (10,)
            print('kwargs:',kwargs)
            start = time.time()
            # *args = *(10,)10
            res = func(*args,**kwargs) # 真正的index()
            end = time.time()
            print(end - start)
            
            return res
        return f1
    
    @deco  # 语法糖(更精简的代码) index = deco(index)
    def index(x,a=1):
        print('x',x)
        print('a',a)
        print('hello index')
        time.sleep(1)
        return 123
    
    # 重新创建的index = deco(index真正的index)
    index = deco(index) # index = f1
    res = index(10) # f1(1)
    

    3 三层装饰器

    三层装饰器:给双层装饰器加参数

    # 判断账号密码来自于哪个地方
    def auth(engine):
        def login(func):
            def inner(*args, **kwargs):
                # 登录功能
                if engine == 'file':
                    username = input('username:')
                    pwd = input('pwd:')
                    if username == 'nick' and pwd == '123':
                        print('登录成功')
                        res = func(*args, **kwargs)  # shopping()
                        return res
                    else:
                        print('登录失败')
                elif engine == 'db':
                    print('账号密码来自于数据库,非法请求')
    
            return inner
        return login
    
    @auth('db')
    def shopping():
        print('shopping')
    
    # login = auth('db') # login = login
    # shopping = login(shopping) # shopping = inner
    shopping() # inner()
    

    4 装饰器模板

    4.1 双层装饰器

    def outter(func):
        def wrapper(*args,**kwargs): # wrapper 是未来要运行的函数
            # 加功能
            res = func(*args,**kwargs) # func是被装饰的函数
            return res
        return wrapper
    
    @outter
    def shopping():
        print('shopping')
    

    4.2 三层装饰器

    def sanceng(engine):
        def outter(func):
            def wrapper(*args, **kwargs):  # wrapper 是未来要运行的函数
                # 加功能
                print(engine)
                res = func(*args, **kwargs)  # func是被装饰的函数
                return res
    
            return wrapper
        return outter
    
    @sanceng('file')
    def shopping():
        print('shopping')
    

    4.3 叠加装饰器

    def outter1(func): # func = wrapper2
        def wrapper1(*args,**kwargs): # wrapper 是未来要运行的函数
            print('---------')
            res = func(*args,**kwargs) # func是被装饰的函数 # wrapper2
            print('---------')
            return res
        return wrapper1
    
    def outter2(func): # func = index
        def wrapper2(*args,**kwargs): # wrapper 是未来要运行的函数
            print('1111111111')
            res = func(*args,**kwargs) # func是被装饰的函数 # index()
            print('1111111111')
            return res
        return wrapper2
    
    # @outter1  # index = outter1(index)
    # @outter2  # index = outter2(index)  # 先运行最下面的装饰器
    # # index
    def index():
        print('index')
    
    # index重新定义的index = outter2(index 真正的index)
    index = outter2(index)   #  index = wrapper2
    # index再一次重新定义的index = outter1(index重新定义的index,即wrapper2)
    index = outter1(index)  # index  = wrapper1
    index()  # wrapper1()
    
    '''
    ---------
    1111111111
    index
    1111111111
    ---------
    '''
    

    5 迭代器

    5.1 可迭代对象

    具有__iter__方法的对象就是可迭代对象

    x = 1 # 不可迭代对象
    s = 'nick' # 可迭代对象
    s.__iter__()
    lt = [1,2,3] # 可迭代对象
    dic = {'a':1,'b':2} # 可迭代对象
    tup = (1,) # 元组只有一个元素必须得加逗号 # 可迭代对象
    se = {1,2,3}  # 可迭代对象
    f = open('test.py') # 可迭代对象
    def func(): # 不可迭代对象
        pass
    
    # 有__iter__()方法的对象就是可迭代对象,然后除了数字类型和函数之外都是可迭代对象
    
    s = 'nick'
    s_iter = s.__iter__()
    print(s_iter.__next__()) # 基于索引(基于上一次结果)通过__next__进行迭代
    print(s_iter.__next__())
    print(s_iter.__next__())
    print(s_iter.__next__())
    
    dic = {'a':1,'b':2} # 可迭代对象
    dic['a']
    dic_iter = dic.__iter__() # 不依赖索引取值 # 迭代器对象
    print(dic_iter.__next__()) # a
    print(dic_iter.__next__()) # b
    # print(dic_iter.__next__()) # 报错
    

    5.2 迭代器对象

    具有__iter__以及__next__方法的叫做迭代器对象

    缺点:

    1. 取值麻烦,只能一个一个取,并且只能往后取,值取了就没了
    2. 无法使用len()方法获取长度
    s = 'nick' # 可迭代对象,不属于迭代器对象
    s.__iter__()
    lt = [1,2,3] # 可迭代对象,不属于迭代器对象
    dic = {'a':1,'b':2} # 可迭代对象,不属于迭代器对象
    tup = (1,) # 元组只有一个元素必须得加逗号 # 可迭代对象,不属于迭代器对象
    se = {1,2,3}  # 可迭代对象,不属于迭代器对象
    f = open('test.py') # 可迭代对象,迭代器对象
    
    # 只有文件是迭代器对象
    

    5.3 for循环原理

    for循环称为迭代器循环,in后必须是可迭代的对象。

    lt = [1,2,3]
    lt_iter = lt.__iter__()
    while 1:
        try:
            print(lt_iter.__next__())
        except StopIteration:
            break
    
    for i in lt:  # 可迭代对象;迭代器对象 # 不依赖索引取值,而是迭代取值
        print(i)
        
    # 1,首先使用iter把lt变成迭代器对象;对于文件也要使用iter方法把文件再一次iter下
    # 2. 然后使用next方法进行迭代取值
    # 3. 判断StopIteration异常,遇到异常终止
    
    dic ={'a':1,'b':2}
    for i in dic:
        print(i)
    
    # 1. 把lt(可迭代对象/迭代器对象)用__iter__方法转换成迭代器对象
    # 2. 使用__next__取出迭代器里的所有值
    # 3. 使用__next__方法取尽迭代器中的所有值,一定会报错,通过异常捕捉退出while循环
    
    # 解决了不依赖索引取值
    
    f = open('time.py') # 可迭代对象,迭代器对象
    f_iter = f.__iter__()
    print(id(f_iter))
    f_iter_iter = f_iter.__iter__()
    print(id(f_iter_iter)) # 两次打印的id值是一样的
    
    dic ={'a':1,'b':2}
    dic_iter = iter(dic)
    print(next(dic_iter))
    print(next(dic_iter))  # 相当于内置方法
    
  • 相关阅读:
    JAVAWEB 一一框架整合(SSI : Spring+SpringMVC+ ibtis)
    接口一一默认方法
    内部类
    java抽象类的使用
    Node(十)之Mongoose配合Node路由实现邮箱注册登录(Post版)
    Node(九)之Node配合MongoDB实现简单的注册登录
    Node(八)之MongoDB简单应用
    JS案例:Ajax实现简单局域网聊天室
    JS瀑布流懒加载案例
    JS表格小案例
  • 原文地址:https://www.cnblogs.com/yushan1/p/11340656.html
Copyright © 2020-2023  润新知