• 8.12 day13


    闭包函数
    一、什么是闭包?
    闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。

    def outter():
    x = 1

    def inner():
        print(x)
    return inner
    

    f = outter()

    def f2():
    x = 2
    f()

    f2()

    1

    1.1 两种为函数传参的方式
    为函数传参的方式一:使用参数的形式

    def func(x):
    print(x)

    func(1)
    func(1)
    func(1)

    1

    1

    1

    为函数传参的方式二:包给函数

    def outter(x):
    x = 1

    def inner():
        print(x)
    return inner
    

    f = outter(1)
    f()
    f()
    f()

    查看闭包的元素

    print(F"f.closure[0].cell_contents: {f.closure[0].cell_contents}")

    1

    1

    1

    f.closure[0].cell_contents: 1

    举个栗子

    def f2(x):
    def f1():
    print(x)
    return f1

    f1_1 = f2(1) #返回f1 + 1
    f1_1() #调用f1,传参x = 1

    1

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

    应用一(复杂):

    import requests

    def get(url):
    res = requests.get(url)
    print(res)

    get('https://www.baidu.com')
    get('https://www.baidu.com')
    get('https://www.baidu.com')
    get('https://www.cnblogs.com/linhaifeng')
    get('https://www.cnblogs.com/linhaifeng')
    get('https://www.cnblogs.com/linhaifeng')

    https://www.baidu.com

    https://www.baidu.com

    https://www.baidu.com

    https://www.cnblogs.com/linhaifeng

    https://www.cnblogs.com/linhaifeng

    https://www.cnblogs.com/linhaifeng

    应用二(闭包):

    爬取

    import requests

    def func(url):
    def get():
    res = requests.get(url)
    print(res.text)
    return get

    baidu_spider = func('http://www.iqiyi.com/')
    baidu_spider()
    无参装饰器
    装饰器指的是为被装饰器对象添加额外功能,就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。

    一、装饰器使用原则
    装饰器的实现必须遵循两大原则:

    不修改被装饰对象的源代码
    不修改被装饰对象的调用方式
    二、怎么用装饰器?
    改变源代码(index内部代码块被改变):

    import time

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

    index()

    welcome to index

    index run time is -1.0008180141448975

    编写重复代码(index( )和f2( )都调用,而且time代码重复):

    import time

    def index():
    print('welcome to index')
    time.sleep(1)

    def f2():
    print('welcome to index')
    time.sleep(1)

    start = time.time()
    index()
    end = time.time()
    print(F"index run time is {start-end}")

    start = time.time()
    f2()
    end = time.time()
    print(F"f2 run time is {start-end}")

    welcome to index

    index run time is -1.0046868324279785

    welcome to index

    f2 run time is -1.000690221786499

    三、两种传参方式
    第一种传参方式:改变调用方式

    import time

    def index():
    print('welcome to index')
    time.sleep(1)

    def time_count(func):
    start = time.time()
    func() #func()=index(),打印'welcome to index'
    end = time.time()
    print(f"{func} time is {start-end}") #打印

    time_count(index) #运行time_count(),同时传参给func

    welcome to index

    <function index at 0x102977378> time is -1.000748872756958

    第二种传参方式:包给函数-外包

    import time

    def index():
    print('welcome to index')
    time.sleep(1)

    def time_count(func):
    # func = 最原始的index
    def wrapper():
    start = time.time()
    func()
    end = time.time()
    print(f"{func} time is {start-end}")
    return wrapper

    f = time_count(index)

    f()

    index = time_count(index) # index被重新定义,原来的index被覆盖,即index = wrapper,func = index
    index() # wrapper()

    依旧是以index()方式调用

    welcome to index

    <function index at 0x102977730> time is -1.0038220882415771

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

    import time

    def index():
    print('welcome to index')
    time.sleep(1)

    return 123
    

    def time_count(func):
    # func = 最原始的index
    def wrapper():
    start = time.time()
    res = func()
    end = time.time()
    print(f"{func} time is {start-end}")

        return res
    return wrapper
    

    index = time_count(index) #index = wapper, func = index
    res = index() #wapper(index)
    print(f"res: {res}")

    welcome to index

    <function index at 0x102977620> time is -1.0050289630889893

    res: 123

    如果原始的index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper()=index(),所以给wrapper()方法传参即可。

    import time

    def index():
    print('welcome to index')
    time.sleep(1)

    return 123
    

    def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name
    

    def time_count(func):
    # func = 最原始的index
    def wrapper(args, **kwargs):
    start = time.time()
    res = func(
    args, **kwargs)
    end = time.time()
    print(f"{func} time is {start-end}")

        return res
    return wrapper
    

    home = time_count(home) #func = home, home = wrapper
    res = home('egon') #wrapper('egon') = fun('egon') = home('egon') = 'welcome egon to home page' = 'egon'
    print(f"res: {res}") # res = func('egon') = home('egon') = 'egon'

    welcome egon to home page

    <function home at 0x102977378> time is -1.0039079189300537

    res: egon

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

    import time

    def time_count(func):
    # func = 最原始的index
    def wrapper(args, **kwargs):
    start = time.time()
    res = func(
    args, **kwargs)
    end = time.time()
    print(f"{func} time is {start-end}")

        return res
    return wrapper
    

    @time_count # home = time_count(home)
    def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name
    

    @time_count # index = time_count(index)
    def index():
    print('welcome to index')
    time.sleep(1)

    return 123
    

    res = home('egon') #func = home name = 'egon' --> welcome egon to home page --> print(f"{func} time is {start-end}")
    print(f"res: {res}") # egon

    welcome egon to home page

    <function home at 0x102977620> time is -1.0005171298980713

    res: egon

    六、装饰器模板(重要)
    def deco(func):
    def wrapper(args,**kwargs):
    res = func(
    args,**kwargs)
    return res
    return wrapper
    有参装饰器
    无参装饰器套了两层,有参装饰器套了三层。

    import time

    current_user = {'username': None}

    def login(func):
    # func = 最原始的index
    def wrapper(args, **kwargs):
    if current_user['username']:
    res = func(
    args, **kwargs)

            return res
    
        user = input('username: ').strip()
        pwd = input('password: ').strip()
    
        if user == 'nick' and pwd == '123':
            print('login successful')
            current_uesr['usre'] = user
            res = func(*args, **kwargs)
    
            return res
        else:
            print('user or password error')
    
    return wrapper
    

    @login #home = login(home)
    def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name
    

    @login #index = login(index)
    def index():
    print('welcome to index')
    time.sleep(1)

    return 123
    

    res = index() #运行index之前运行糖果 wrapper(index) 继续运行 返回res = func 继续运行 即真正的index()

    username: nick

    password: 123

    login successful

    welcome to index

    对于上面的登录注册,我们把用户登录成功的信息写入内存当中。但是在工业上,用户信息可以存在文本中、mysql中、mongodb当中,但是我们只让用户信息来自于file的用户可以认证。因此我们可以改写上述的装饰器。

    import time

    current_user = {'username': None}

    def login(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):

        if current_user['username']:
            res = func(*args, **kwargs)
    
            return res
    
        user = input('username: ').strip()
        pwd = input('password: ').strip()
        
        engine = 'file'
    
        if engine == 'file':
            print('base of file')
            if user == 'nick' and pwd == '123':
                print('login successful')
                current_uesr['usre'] = user
                res = func(*args, **kwargs)
    
                return res
            else:
                print('user or password error')
        elif engine == 'mysql':
            print('base of mysql')
        elif engine == 'mongodb':
            print('base of mongodb')
        else:
            print('default')
    
    return wrapper
    

    @login
    def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    @login
    def index():
    print('welcome to index')
    time.sleep(1)

    res = index()

    username: nick

    password: 123

    base of file

    login successful

    welcome to index

    一、三层闭包
    def f1(y):

    def f2():
        x = 1
    
        def f3():
            print(f"x: {x}")
            print(f"y: {y}")
            return f3
        return f2
    

    f2 = f1(2) #f2(y = 2)
    f3 = f2() #x = 1
    f3() #到外部找x, y

    倒着运行--->先找x, y--->找到x = 1--->y = 2--->结果输出

    x: 1

    y: 2

    现在需求改了,我们需要判断用户动态的获取用户密码的方式,如果是file类型的,我们则让用户进行认证。因此我们可以使用有参装饰器。

    import time

    current_uesr = {'username': None}

    def auth(engine='file'):

    def login(func):
        # func = 最原始的index
        def wrapper(*args, **kwargs):
    
            if current_user['username']:
                res = func(*args, **kwargs)
    
                return res
    
            user = input('username: ').strip()
            pwd = input('password: ').strip()
    
            if engine == 'file':
                print('base of file')
                if user == 'nick' and pwd == '123':
                    print('login successful')
                    current_uesr['usre'] = user
                    res = func(*args, **kwargs)
    
                    return res
                else:
                    print('user or password error')
            elif engine == 'mysql':
                print('base of mysql, please base of file')
            elif engine == 'mongodb':
                print('base of mongodb, please base of file')
            else:
                print('please base of file')
    
            return wrapper
    
        return login
    

    @auth(engine='mysql')
    def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    @auth(engine='file')
    def index():
    print('welcome to index')
    time.sleep(1)

    res = index()

    username: nick

    password: 123

    base of file

    login successful

    welcome to index

    注意:由于两层的装饰器,参数必须得固定位func,但是三层的装饰器解除了这个限制。我们不仅仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也就是说装饰器三层即可,多加一层反倒无用。

    迭代器
    迭代器:迭代的工具。

    迭代是更新换代,比如你子孙繁衍;迭代也可以说成是重复,但每一次的重复都是基于上一次的结果来的,例如计算机中的迭代开发,就是基于软件的上一个版本更新。

    以下代码就不是迭代,它只是单纯的重复

    while True:
    print(''10)

    一、可迭代对象
    定义:具有__iter__方法的对象就是可迭代对象,除了数字类型和函数类型。

    注意:tuple(1)与tuple(1,)类型有区别

    x = 1.iter # SyntaxError: invalid syntax

    以下都是可迭代的对象

    name = 'nick'.iter
    lis = [1, 2].iter
    tup = (1, 2).iter
    dic = {'name': 'nick'}.iter
    s1 = {'a', 'b'}.iter
    f = open('49w.txt', 'w', encoding='utf-8')
    f.iter
    f.close()
    二、迭代器对象
    只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的。因此我们得找到一个方法能让其他的可迭代对象不依赖索引取值。

    定义:具有__iter__和__next__方法的都是迭代器对象,只有文件。

    缺点:

    取值麻烦,只能一个一个取,并且只能往后取,值取了就没了
    无法使用len()方法获取长度

    不依赖索引的数据类型迭代取值

    dic = {'a': 1, 'b': 2, 'c': 3}
    iter_dic = dic.iter()
    print(iter_dic.next())
    print(iter_dic.next())
    print(iter_dic.next())

    print(iter_dic.next()) # StopIteration:

    a

    b

    c

    依赖索引的数据类型迭代取值

    lis = [1, 2, 3]
    iter_lis = lis.iter()
    print(iter_lis.next())
    print(iter_lis.next())
    print(iter_lis.next())

    print(iter_lis.next()) # StopIteration:

    1

    2

    3

    上述的方法是非常繁琐的,我们可以使用while循环精简下。其中使用的try...except...为异常处理模块

    for循环原理

    lt = [1,2,3]

    lt_iter = lt.iter()
    while 1:
    try:
    print(lt_iter.next())
    except StopIteration:
    break
    注意一:迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象

    注意二:for循环 == 迭代循环

    注意三:迭代器对象使用__iter__()还是迭代器对象

  • 相关阅读:
    67. Add Binary
    66. Plus One
    64. Minimum Path Sum
    63. Unique Paths II
    How to skip all the wizard pages and go directly to the installation process?
    Inno Setup打包之先卸载再安装
    How to change the header background color of a QTableView
    Openstack object list 一次最多有一万个 object
    Openstack 的 Log 在 /var/log/syslog 里 【Ubuntu】
    Git 分支
  • 原文地址:https://www.cnblogs.com/bjlxxbj/p/11342301.html
Copyright © 2020-2023  润新知