zoukankan      html  css  js  c++  java
  • 函数进阶(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))  # 相当于内置方法
    
  • 相关阅读:
    百度mp3地址解密码
    VB 在EXE后附加信息
    截屏函数
    Base64和StrToByte
    The Android ION memory allocator, DMABUF is mentioned as well
    DDC EDID 介绍
    Memory management for graphic processors TTM的由来
    科普 写display driver的必看 How video card works [2D的四种主要操作]
    GEM vs TTM
    DMABUF 背景介绍文章 Sharing buffers between devices
  • 原文地址:https://www.cnblogs.com/yushan1/p/11340656.html
Copyright © 2011-2022 走看看