zoukankan      html  css  js  c++  java
  • 函数(二)

    闭包

    闭包现象

    正常来说,函数调用结束, 函数体里的变量都会被销毁, 而有一种现象是当函数执行完毕, 函数体里的变量不会被销毁, 因为这个变量被内嵌函数的一段代码调用着,无法销毁, 这种现象叫做闭包

    def outer():
        name='周泽SB'
        def inner():
            print(name)
        return inner
    
    func_inner=outer()  # 返回的是inner这个内层函数对象加上调用的变量name的作用域
    func_inner()
    

    函数进阶-装饰器

    闭包函数的一种, 主要场景是一段程序执行前需要判断是否是否登录

    实现这个功能还要符合开放封闭原则 ( 不改变程序的源代码以及调用方式进行扩展)

    源程序

    def home():
        print('主页')
    
    
    def america():
        print('----欧美专区----')
    
    
    def japan():
        print('----日韩专区----')
    
    home()
    america()
    japan()
    

    初级版

    需要对america, japan加入登录验证

    account = {
        'is_authenticated': False,
        'username': 'zzsb',
        'password': '123',
    }
    
    
    def login(func):
        if not account['is_authenticated']:
            usr, pwd = input('请输入用户名 ').strip(), input('请输入密码 ').strip()
            username, password = account.get('username'), account.get('password')
            if usr == username and pwd == password:
                print('登入成功')
                account['is_authenticated'] = True
                return func
            else:
                print('用户名或密码错误')
    
        else:
            print('用户已登录,认证通过')
            return func
    
    
    def home():
        print('主页')
    
    
    def america():
        print('----欧美专区----')
    
    
    def japan():
        print('----日韩专区----')
    
    
    america = login(america)
    america()
    
    japan = login(japan)
    japan()
    

    使用闭包函数实现功能(装饰器的本质)

    account = {
        'is_authenticated': False,
        'username': 'zzsb',
        'password': '123',
    }
    
    
    def login(func):
        def inner():
            if not account['is_authenticated']:
                usr, pwd = input('请输入用户名 ').strip(), input('请输入密码 ').strip()
                username, password = account.get('username'), account.get('password')
                if usr == username and pwd == password:
                    print('登入成功')
                    account['is_authenticated'] = True
                    func()
                else:
                    print('用户名或密码错误')
    
            else:
                print('用户已登录,认证通过')
                func()
        return inner
    
    def home():
        print('主页')
    
    
    def america():
        print('----欧美专区----')
    
    
    def japan():
        print('----日韩专区----')
    
    
    america = login(america)
    america()
    
    japan = login(japan)
    japan()
    

    高级版

    如果被要求登录认证的函数是有参数的,上面的代码就会报错

    account = {
        'is_authenticated': False,
        'username': 'zzsb',
        'password': '123',
    }
    
    
    def login(func):
        def inner(*args,**kwargs):
            if not account['is_authenticated']:
                usr, pwd = input('请输入用户名 ').strip(), input('请输入密码 ').strip()
                username, password = account.get('username'), account.get('password')
                if usr == username and pwd == password:
                    print('登入成功')
                    account['is_authenticated'] = True
                    func(*args,**kwargs)
                else:
                    print('用户名或密码错误')
    
            else:
                print('用户已登录,认证通过')
                func(*args,**kwargs)
    
        return inner
    
    
    def home():
        print('主页')
    
    
    def america():
        print('----欧美专区----')
    
    
    def japan(vip_level):
        if vip_level > 3:
            print('解锁高级玩法')
        else:
            print('----日韩专区----')
    
    
    america = login(america)
    america()
    
    japan = login(japan)
    japan(4)
    

    python装饰器用法

    在需要进行登录验证的函数上加上@装饰器函数

    account = {
        'is_authenticated': False,
        'username': 'zzsb',
        'password': '123',
    }
    
    
    def login(func):
        def inner(*args,**kwargs):
            if not account['is_authenticated']:
                usr, pwd = input('请输入用户名 ').strip(), input('请输入密码 ').strip()
                username, password = account.get('username'), account.get('password')
                if usr == username and pwd == password:
                    print('登入成功')
                    account['is_authenticated'] = True
                    func(*args,**kwargs)
                else:
                    print('用户名或密码错误')
    
            else:
                print('用户已登录,认证通过')
                func(*args,**kwargs)
    
        return inner
    
    
    def home():
        print('主页')
    
    
    @login
    def america():
        print('----欧美专区----')
    
    @login
    def japan(vip_level):
        if vip_level > 3:
            print('解锁高级玩法')
        else:
            print('----日韩专区----')
    
    
    america()
    japan(4)
    

    列表生成式

    将列表的值的元素每一个加1

    • 使用lambda函数
    a = [1, 2, 3, 4, 5]
    
    res = map(lambda x: x + 1, a)
    print(list(res))
    
    • 使用列表生成式
    a = [1, 2, 3, 4, 5]
    ls = [i+1 for i in a]
    print(ls)
    

    生成器

    range在python2和python3的区别

    • python2环境下自动生成数字存入对象

      >>> range(10)
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      
    • python3中只是一个生成器对象

    >>> range(10)
    range(0, 10)
    

    引子

    • for循环生成100000000 个数字
    import time
    start= time.time()
    for i in range(100000000):
        if i == 100:
            break
        print(i)
    print(time.time()-start) # 2.91226005554
    
    • while循环生成100000000 个数字
    import time
    
    start = time.time()
    count = 0
    while count < 100000000:
        count += 1
        if count > 100:
            break
    print(time.time() - start)  # 0.000188112258911
    

    什么是生成器

    以上2个例子:

    for循环执行效率更慢, 因为先生成1-100000000的列表,再进行判断, 这种占用大量内存空间

    while循环是通过某种算法( 每次自加1)计算出下一次循环的数据, 根据需要进行取值, 这种占用内存更少

    在python中, 这种一边循环一边计算下一次循环的值的机制就是生成器, 也可理解为一种数据类型

    创建生成器

    >>> (x*x for x in range(10)) 
    <generator object <genexpr> at 0x10ddf5a50>
    

    生成器取值

    通过next取值

    >>> test=(x*x for x in range(5))
    >>> test
    <generator object <genexpr> at 0x103979d58>
    >>> next(test)
    0
    >>> next(test)
    1
    >>> next(test)
    4
    >>> next(test)
    9
    >>> next(test)
    16
    >>> next(test)  # 取不到值就会报错
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    取出所有值

    >>> test=(x*x for x in range(5))
    >>> for i in test:
    ...     print(i)
    ... 
    0
    1
    4
    9
    16
    

    函数生成器

    实现斐波那契数列

    1 2 3 5 8 13....

    count = 0
    a = 0
    b = 1
    
    while count < 20:
        old_a = a
        a = b
        b = old_a + a
    
        '''
        第一次循环: old_a=0 a=1  b=1
        第二次循环: old_a=1 a=1  b=2
        第三次循环: old_a=1 a=2  b=3
        第四次循环: old_a=2 a=3  b=5
        '''
    
        print(b)
        count += 1
    

    通过生成器实现斐波那契数列

    def MakeServer(n):
        '''
        生成器函数
        '''
        count = 0
        a = 0
        b = 1
    
        while count < n:
            old_a = a
            a = b
            b = old_a + a
    
            '''
            第一次循环: old_a=0 a=1  b=1
            第二次循环: old_a=1 a=1  b=2
            第三次循环: old_a=1 a=2  b=3
            第四次循环: old_a=2 a=3  b=5
            '''
    
            yield b  # 暂停并返回b的值, 下面的代码通过next()函数触发才会执行
            count += 1
    
    obj=MakeServer(6)
    
    print(obj.__next__())
    print(obj.__next__())
    print(obj.__next__())
    print(obj.__next__())
    print('----生成器----')
    print(obj.__next__())
    print(obj.__next__())
    

    Yield接收外部输入的值

    错误代码

    TypeError: can't send non-None value to a just-started generator

    def g_test():
        while True:
            n = yield
    
            print('recieve from outside', n)
    
    g=g_test()
    
    for i in range(10):
        g.send(i)
    

    解决方案

    先发送一个None给到生成器

    def g_test():
        while True:
            n = yield
    
            print('recieve from outside', n)
    
    g=g_test()
    g.send(None)  # 调用生成器, 同时会发送None到Yield
    
    for i in range(10):
        g.send(i) # 调用生成器, 同时发送i
    
    def g_test():
        while True:
            n = yield
    
            print('recieve from outside', n)
    
    g=g_test()
    g.__next__()  # 调用生成器, 同时会发送None到Yield
    
    for i in range(10):
        g.send(i) # 调用生成器, 同时发送i
    

    实现单线程下的多并发

    def consumer(name):
        print('消费者%s准备吃包子了...' % name)
        while True:
            baozi_num = yield
    
            print('消费者%s吃了包子%s' % (name, baozi_num))
    
    
    c1 = consumer('c1')
    c2 = consumer('c2')
    c3 = consumer('c3')
    
    c1.__next__()
    c2.__next__()
    c3.__next__()
    for i in range(1, 6):
        print('-------生成了第%s批包子-------' % i)
        c1.send(i)
        c2.send(i)
        c3.send(i)
    

    迭代器

    可迭代对象

    直接作用于for循环的对象统称为可迭代对象 ( 可以被循环 )

    • 判断一个对象是否是Iterable对象
    >>> from collections import Iterable
    >>> isinstance([],Iterable)
    True
    >>> isinstance({},Iterable)
    True
    >>> isinstance('abc',Iterable)
    True
    >>> isinstance((x for x in range(10)),Iterable)
    True
    >>> isinstance(100,Iterable)
    False
    
    • 哪些数据类型可以直接作用于for循环
    1. 集合类型数据 , list, tuple, dict, set, str等
    2. generator, 包括生成器和带yield的generator function

    什么是迭代器

    可以被next() 函数调用并不断返回下一个值的对象称为迭代器: Iterator

    • 判断一个对象是否是Iterator
    >>> from collections import Iterator
    >>> isinstance(1,Iterator)
    False
    >>> isinstance({},Iterator)
    False
    >>> isinstance([],Iterator)
    False
    >>> isinstance('周泽SB',Iterator)
    False
    >>> isinstance((i for i in range(10)),Iterator)  # 生成器对象是迭代器对象
    True
    >>> iter({})  # 可迭代对象通过调用函数iter()可转换为迭代器对象 
    <dict_keyiterator object at 0x10a9ad1d8>
    >>> isinstance(iter({}),Iterator)
    True
    >>> isinstance(iter([]),Iterator)
    True
    >>> isinstance(iter('周泽SB'),Iterator)
    True
    
  • 相关阅读:
    常用的正则表达式
    Spring
    Hibernate-04
    Hibernate-03
    Hibernate-02
    Hibernate-01
    装饰器(python)
    软件工程之小组选题报告
    小组项目之需求分析与原型设计
    关于group_concat函数拼接字符超长的问题
  • 原文地址:https://www.cnblogs.com/cjwnb/p/11608937.html
Copyright © 2011-2022 走看看