zoukankan      html  css  js  c++  java
  • day04

    一、 闭包函数

    一 什么是闭包?

    内部函数包含对外部作用域而非全局作用域的引用
    
    #提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来喽,包起呦,包起来哇
    

     示例:

    def outter():
        x=110
        def inner():
            print(x)
        return inner
    
    
    f=outter() #这里是把返回值赋值给f
    f() #然后在用f调用函数

    二 闭包的意义与应用

    #闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
    #应用领域:延迟计算(原来我们是传参,现在我们是包起来)

    from urllib.request import urlopen #加载爬虫模块
    def index(url):
        def get():
            return urlopen(url).read()
        return get
    baidu=index('http://www.baidu.com') #传入函数参数
    print(baidu().decode('utf-8'))

    二、 装饰器

    装饰器就是闭包函数的一种应用场景

    开放封闭原则:对修改封闭,对扩展开放

    二 什么是装饰器

    装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
    强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
    装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

    三 装饰器的使用

    一个简单的装饰器案例

    
    
    #inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
    import time

    def timmer(func): #func 就是被装饰对象的内存地址
    # func=index
    #时间闭包函数
    def inner():
    start_time = time.time()
    func()
    stop_time = time.time()
    print('run time is %s' % (stop_time - start_time))
    return inner #把内部函数返回出去,方便外面调用

    @timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
    def index():
    time.sleep(3)
    print("welcome to index page")
    index()

     解决home传参问题

    #inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
    import time
    
    def timmer(func):
        # func=index
    #时间闭包函数
        def inner(*args,**kwargs):  #这里用args 接受所有参数
            start_time = time.time()
            func(*args,**kwargs)  #这原样返回
            stop_time = time.time()
            print('run time is %s' % (stop_time - start_time))
        return inner #把内部函数返回出去,方便外面调用
    
    @timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
    # def index():
    #     time.sleep(3)
    #     print("welcome to index page")
    # index()
    def home(name):
        time.sleep(3)
        print("welcome to home %s page"%(name))
    home('sunkedong')

    带有返回值的装饰器
    #inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
    import time
    
    def timmer(func):
        # func=index
    #时间闭包函数
        def inner(*args,**kwargs):
            start_time = time.time()
            res=func(*args,**kwargs)
            stop_time = time.time()
            print('run time is %s' % (stop_time - start_time))
            return res  #这里的意思是把上面res保存的结果返回出去,在外面需要调用
        return inner #把内部函数返回出去,方便外面调用
    
    @timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
    def index():
        time.sleep(1)
        print("welcome to index page")
        return "index-res"  #存一个测试的返回值
    res=index() #把返回值保存到变量中
    print(res)#打印,下面的home是一样的原理
    @timmer
    def home(name):
        time.sleep(1)
        print("welcome to home %s page"%(name))
        return "home-res"
    res=home('sunkedong')
    print(res)

    用户登录装饰器

    第一步

    import time
    def login(func):
        # func=index
        def inner(*args,**kwargs):
            name=input('username>>').strip()
            pwd=input('password>>').strip()
            if name == "sunkd" and pwd == "sunkd":
                res=func(*args,**kwargs)
                return res
        return inner
    
    @login
    def index():
        time.sleep(1)
        print("login success...")
        print("welcome to index page")
        return "index_ok"
    @login
    def home(name,age):
        time.sleep(1)
        print("login success...")
        print('welcome to %s home page,age is %s '%(name,age))
        return "home_ok"home('sunkd',22)
    index()

    第二步、修复两次登录的bug

    import time
    current_status={'user':None,'login_status':False}
    def login(func):
        # func=index
        def inner(*args,**kwargs):
            #下面是判断登录状态,如果字典有内容,并且为True 那么直接执行函数,否则跳到登录
            if current_status['user'] and current_status['login_status'] == True:
                res = func(*args, **kwargs)
                return res
            else:
                name=input('username>>').strip()
                pwd=input('password>>').strip()
                if name == "sunkd" and pwd == "sunkd":
                    print('login sucess.')
                    #登录成功后,记录状态
                    res=func(*args,**kwargs)
                    current_status['user']=name
                    current_status['login_status']=True
                    return res
        return inner
    
    @login
    def index():
        time.sleep(1)
        print("welcome to index page")
        return "index_ok"
    @login
    def home(name,age):
        time.sleep(1)
        print('welcome to %s home page,age is %s '%(name,age))
        return "home_ok"
    
    index()
    home('sunkd',22)

     三、带参数的装饰器

    import time
    current_status={'user':None,'login_status':False}
    
    def auth(user_type='mysql'): #这里可以定义一个默认参数。后面可以重新赋值。
        # user_type='file'
        def login(func):
            def inner(*args,**kwargs):
                #下面是判断登录状态,如果字典有内容,并且为True 那么直接执行函数,否则跳到登录
                if current_status['user'] and current_status['login_status'] == True:
                    res = func(*args, **kwargs)
                    return res
                if user_type == 'file':
                    u='sunkd'
                    p='sunkd'
                elif user_type == 'mysql':
                    print('mysql auth')
                elif user_type == 'ldap':
                    print('ldap auth')
                else:
                    print('no fount the auth type')
                    exit(2)
                #下面开始用户登录
                name = input('username>>').strip()
                pwd = input('password>>').strip()
                if name == u and pwd == p :
                    print('login sucess.')
                    # 登录成功后,记录状态
                    res = func(*args, **kwargs)
                    current_status['user'] = name
                    current_status['login_status'] = True
                    return res
            return inner
        return login
    #下面返回的其实还是inner的函数
    @auth(user_type='file1')
    def index():
        time.sleep(1)
        print("welcome to index page")
        return "index_ok"
    index()
    
    # #下面这种调用方式比较原始,做为理解使用
    # index=auth(user_type='file')(index) #这里就重新赋值了。会打印file
    # index()

    加多个装饰器

    import time
    current_status={'user':None,'login_status':False}
    
    def timmer(func):
        def inner(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is :[%s]' %(stop_time-start_time))
            return res
    
        return inner
    
    def auth(egine='file'):
        # egine='file'
        def wrapper(func):
            def inner(*args,**kwargs):
                if current_status['user'] and current_status['login_status']:
                    res = func(*args, **kwargs)
                    return res
    
                if egine == 'file':
                    u='egon'
                    p='123'
                elif egine == 'mysql':
                    u = 'egon'
                    p = '123'
                elif egine == 'ldap':
                    u = 'egon'
                    p = '123'
                else:
                    pass
                name = input('username>>:').strip()
                pwd = input('password>>:').strip()
                if name == u and pwd == p:
                    print('login successfull')
                    current_status['user'] = name
                    current_status['login_status'] = True
                    res = func(*args, **kwargs)
                    return res
            return inner
        return wrapper
    
    
    @timmer
    @auth(egine='ldap') #@wrapper #index=wrapper(timmer_inner)
    # @timmer #timmer_inner=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index page')
        return 123
    
    
    index() #inner()

    三、迭代器

    '''
    1 什么叫迭代:迭代是一个重复过程,每次重复都是基于上一次的结果来的
    2 为什么要用迭代器?

    l=['a','b','c']
    n=0
    while n < len(l):
    print(l[n])
    n+=1


    - 对于序列类型:字符串,列表,元组,可以使用基于索引的迭代取值方式,而对于没有索引的类型,如字典,
    集合、文件,这种方式不再适用,于是我们必须找出一种能不依赖于索引的取值方式,这就是迭代器

    3 可迭代的对象:只要对象内置有__iter__方法,obj.__iter__
    4 迭代器对象:对象既内置有__iter__方法,又内置有__next__,如文件对象
    注意:可迭代对象不一定是迭代器对象,而迭代器对象一定是可迭代的对象

    '''
    #可迭代的对象

    # 'hello'.__iter__
    # [1,2].__iter__
    # (1,2).__iter__
    # {'a':1}.__iter__
    # {1,2,3}.__iter__
    #

    #既是可迭代对象,又是迭代器对象

    # open('a.txt','w').__iter__
    # open('a.txt','w').__next__

    # 迭代器对象执行__iter__得到的仍然是它本身

    # dic={'a':1,'b':2,'c':3}
    # iter_dic=dic.__iter__()
    #
    # print(iter_dic.__iter__() is iter_dic)

    # f=open('a.txt','w')
    # print(f is f.__iter__())


    #迭代器对象的用处

    # dic={'a':1,'b':2,'c':3}
    # iter_dic=dic.__iter__()
    
    
    # print(iter_dic.__next__())
    # print(next(iter_dic))
    # print(next(iter_dic))
    # print(next(iter_dic)) #StopIteration
    
    
    # with open('a.txt','r') as f:
    # print(next(f))
    # print(next(f))
    # print(next(f))
    
    
    # l=[1,2,3,4,5]
    # iter_l=l.__iter__()
    # print(iter_l)
    # print(next(iter_l))
    # print(next(iter_l))
    # print(next(iter_l))

    #基于迭代器对象的迭代取值(不依赖索引)

    dic={'a':1,'b':2,'c':3}
    
    iter_dic=dic.__iter__()
    obj=range(1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
    
    # list(obj)
    
    
    # while True:
    # try:
    # i=next(iter_dic)
    # print(i)
    # except StopIteration:
    # break
    #
    
    # for i in dic: #iter_dic=dic.__iter__()
    # print(i)


    '''
    迭代器的优缺点:
    - 优点:
    提供了一种统一的迭代取值方式,该方式不再依赖于索引
    更节省内存

    - 缺点:
    无法统计长度
    一次性的,只能往后走,不能往前退,无法获取指定位置的值
    '''

    from collections import Iterable,Iterator
    
    print(isinstance('hello',Iterable))
    print(isinstance('hello',Iterator))
    四、生成器

    定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行函数体代码,会到到一个结果
    该结果就是生成器对象

    #
    # def func():
    # print('===>first')
    # yield 1
    # print('===>second')
    # yield 2
    # print('====>third')
    # yield 3
    #
    #
    # g=func()
    # print(g)

    #生成器本质就是迭代器

    # print(next(g))
    # print(next(g))
    # print(next(g))
    # print(next(g))
    
    
    # print(next(func()))
    # print(next(func()))
    # print(next(func()))
    # for i in g:
    # print(i)
    #
    # for i in g:
    # print(i)
    #
    # for i in g:
    # print(i)
    
    '''

    yield的功能:
    - 为我们提供了一种自定义迭代器的方式
    - 对比return,可以返回多次值,挂起函数的运行状态

    '''

    #自定义功能,可以生成无穷多个值,因为同一时间在内存中只有一个值

    # def my_range(start,stop,step=1):
    # while start < stop:
    # yield start
    # start+=step
    
    
    # g=my_range(1,5,2) #1 3
    # print(next(g))
    # print(next(g))
    # print(next(g))
    # print(next(g))
    # print(next(g))
    #
    # for i in my_range(1,1000000000000000000000000000000000000000000,step=2):
    # print(i)
    
     
    
    
    # tail -f access.log | grep '404'
    # import time
    # def tail(filepath):
    # with open(filepath,'rb') as f:
    # f.seek(0,2)
    # while True:
    # line=f.readline()
    # if line:
    # yield line
    # else:
    # time.sleep(0.2)
    #
    # def grep(pattern,lines):
    # for line in lines:
    # line=line.decode('utf-8')
    # if pattern in line:
    # yield line
    #
    # g=grep('404',tail('access.log'))
    # for line in g:
    # print(line)
    
     


    #yield的表达式形式的应用

    # def eater(name):
    # food_list=[]
    # print('%s 开动啦' %name)
    # while True:
    # food=yield food_list #food=‘骨头’
    # print('%s 开始吃 %s' %(name,food))
    # food_list.append(food)
    #
    # g=eater('alex')
    
    # g.send(None) #next(g)
    # print(g.send('骨头'))
    # print(g.send('shi'))
    
     
    
    # def f1():
    # while True:
    # x=yield
    # print(x)
    #
    # g=f1()
    # next(g)
    # g.send(1)
    # g.send(1)
    # g.close()
    # g.send(1)
    # g.send(1)
    # g.send(1)

    二元表达式

     def my_max(x,y):
        return x if x > y else y

    列表解析 与生成器表达式

    egg_list=[]
    for i in range(10):
        if i >= 3:
            res='egg%s' %i
            egg_list.append(res)
    
    
    names=['egon','alex_sb','wupeiqi','yuanhao']
    
    names=[name.upper() for name in names if not name.endswith('sb')]
    print(names)
    #1、把列表推导式的[]换成()就是生成器表达式
    
    #2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
    >>> chicken=('鸡蛋%s' %i for i in range(5))
    >>> chicken
    <generator object <genexpr> at 0x10143f200>
    >>> next(chicken)
    '鸡蛋0'
    >>> list(chicken) #因chicken可迭代,因而可以转成列表
    ['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4',]
    
    #3、优点:省内存,一次只产生一个值在内存中


  • 相关阅读:
    java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header.
    spring-session-data-redis依赖冲突问题
    centos7启动iptables时报Job for iptables.service failed because the control process exited with error cod
    图片上传后台服务报内存溢出 Out Of Memory Java heap space
    mysql 数据库密码忘记重置 进行远程连接
    打Jar包
    Type interface com.innovationV2.mapper.UserMapper is not known to the MapperRegistry
    关于java基础类型Integer String的clone()
    clion使用clang编译
    token & refresh token 机制总结
  • 原文地址:https://www.cnblogs.com/sunkedong/p/7599522.html
Copyright © 2011-2022 走看看