• 闭包函数,装饰器,迭代器,生成器,yield,


    闭包函数

    包含对外的作用域,在内部定义函数,引用自身函数外的函数,

    name ='alex'
    def func() :
    name ='egon'
    def bar() :
    print(name) #name属于外层func(),引用外部的函数变量,先找外面一层的
    return bar
    b=func()
    b()---结果 egon

    闭包函数不受定义级别的限制,任何位置都可用,
    f._closure_闭合的意思,所有的闭包函数都有这个 属性
    特点:
    自带作用域,自己就带着一层,所以先找外部作用域,
    延迟计算,什么时候用,什么时候执行func()

    例子:一直又钱:
    def f() :
    money=100
    def tell_infor(name): ----
    print('%s have money %s' %(name,money))-----先找tell_infor是否money有值,没有,再向外找,
    tell_infor('egon')
    f()
    ---egon have money 100
    总结:想给函数一种状态,就把函数定义在内部,在这个外部定一个变量,还要不受位置限制,就用return返回,
    例子2:
    def b():
    money=100
    def c():
    print('egon have money %s' %(money))

    return c

    c=b()
    def foo():
    money=1
    c()
    foo() ----egon have money 100
    解析:money在b()已经被定义,所以在foo()再调用从C(时不会从foo()里去找,
    ----
    闭包函数的基本形式:
    def 外部函数名():
       内部函数需要的变量
       def 内部函数():
          引用外部的变量
       return 内部函数
    ----
    def deco():
    x=1 #x=1就x写死了,可以写在 deco(x)里,当做参数,
    def wrapper():
    print(x) #调用外面函的参数
    return wrapper

    wrapper=deco() #deco()函数赋给wrapperwrapper就有了全局作用域
    wrapper() #执行wrapper函数
    ---结果 1

    -------闭包函数的应用场景-------------

    提取网页链接,网页下载
    from urllib.request import urlopen ---导入模块
    def url_func(url):
    def wrapper():
    return urlopen(url).read()
    return wrapper

    python=url_func('http://www.python.org')
    print(python())
    --- 结果 b'<!doctype html> <!--[if lt IE 7]>  
    <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]--> <!--[if IE 7]> ......
    ============================
    软件开发原则
    开发封闭原则
    1.对扩展是开发的,增加功能
    2.对修改是封闭的,对源代码,函数,不宜修改,影响全局

    =============================================
    装饰器
    功能:不修改被装饰对象的源代码,以及被装饰对象的调用方式的前提下,对其增加新功能。
    原则:不修改源代码,不修改调用方式,
    目标:增加新功能

    例子:在index的基本功能上增加,函数到底运行了多久,就知道了index的网络延迟
    
    
    import time  #导入时间模块
    import random #导入用于生成随机数模块

    def timmer(func): #装饰器timmer.可以用在index函数,也可以用在别的函数上
    #func=index() 可以直接当做timmer 的参数,更灵活,
    def wrapper():
    start_time=time.time() #功能开始时间,
    func() #不能写死,赋给一个变量,index()=func
    stop_time=time.time() #功能结束时间
    print('run time is %s' %(stop_time-start_time))
    return wrapper #一定要返回wrapper值,


    @timmer #用语法实现装饰器的功能,
    def index():#index的函数功能是在4秒的时间内显示出网页的内容,还想要增加新功能,就要添加新功能,就用到了装饰器
    time.sleep(random.randrange(1,5))
    print('welcome to index page')
    index()
    ---结果
    welcome to index page #原功能 ,
    run time is 1.0044817924499512 #新增装饰器的功能,函数的运行时间

    解析:没有修改源码,没有改变调用方式,增加了新功能,,

    ------

    装饰器

    
    
    阅读: 229372
    
    
    
    

    由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

    >>> def now():
    ...     print '2013-12-25'
    ...
    >>> f = now
    >>> f()
    2013-12-25
    

    函数对象有一个__name__属性,可以拿到函数的名字:

    >>> now.__name__
    'now'
    >>> f.__name__
    'now'
    

    现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

    本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:

    def log(func):
        def wrapper(*args, **kw):
            print 'call %s():' % func.__name__
            return func(*args, **kw)
        return wrapper
    

    观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

    @log
    def now():
        print '2013-12-25'
    

    调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

    >>> now()
    call now():
    2013-12-25
    

    @log放到now()函数的定义处,相当于执行了语句:

    now = log(now)
    

    由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

    wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

    如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:

    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print '%s %s():' % (text, func.__name__)
                return func(*args, **kw)
            return wrapper
        return decorator
    

    这个3层嵌套的decorator用法如下:

    @log('execute')
    def now():
        print '2013-12-25'
    

    执行结果如下:

    >>> now()
    execute now():
    2013-12-25
    

    和两层嵌套的decorator相比,3层嵌套的效果是这样的:

    >>> now = log('execute')(now)
    

    我们来剖析上面的语句,首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

    以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

    >>> now.__name__
    'wrapper'
    

    因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

    import functools
    
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print 'call %s():' % func.__name__
            return func(*args, **kw)
        return wrapper
    

    或者针对带参数的decorator:

    import functools
    
    def log(text):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                print '%s %s():' % (text, func.__name__)
                return func(*args, **kw)
            return wrapper
        return decorator
    

    import functools是导入functools模块。模块的概念稍候讲解。现在,只需记住在定义wrapper()的前面加上@functools.wraps(func)即可。

    小结

    在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。

    decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。

    请编写一个decorator,能在函数调用的前后打印出'begin call''end call'的日志。

    再思考一下能否写出一个@log的decorator,使它既支持:

    @log
    def f():
        pass
    

    又支持:

    @log('execute')
    def f():
        pass
    




    ============================
    迭代器
    1.重复 2.下次的重复基于上次的结果
    模拟迭代
    while True :
    cmd = input('>>:')
    print(cmd)# 只重复,不迭代

    l=['a','b','c']
    count=0
    while count < len(l) :
    print(l[count])
    count+=1 #每次的结果都是基于上次

    有序列的数据类型,都有索引
    l=['a','b','c']
    for count in range(len(l)) :
    print(l[count]) #依赖索引求值
    
    
    #没有索引取值
    d={'a':1,'b':2,'c':3}
    for k in d:
    print(d[k]) #得到1,2,3
    print(k) #得到a,b,c
    Python提供一种不依赖索引的迭代方式,
    给一些对象内置了__iter__方法,只要对象有__iter__称为可迭代对象
    -------------------------------
    s1.__iter__() #字符串是可迭代对象
    l=[1,2,3]
    l.__iter__() #列表是可迭代对象
    t=(1,2,3)
    t.__iter__() #元组是可迭代对象
    set={1,2,3}
    set.__iter__() #集合是可迭代对象
    f=open('1.txt',encoding='utf-8')
    f.__iter__() #文件是可迭代对象
    d={'a':1,'b':2,'c':3}
    d.__iter__() #字典是可迭代对象
    --------------------------------------------
    作用:执行obj.__iter__() 得到的结果就是迭代器
    得到迭代器既有__iter__() 要得到值还要用 __next__()方法
    d={'a':1,'b':2,'c':3}
    a=d.__iter__() #字典是可迭代对象 a就是迭代器
    print(a)-----结果 <dict_keyiterator object at 0x00000116709D85E8>
    d={'a':1,'b':2,'c':3}
    a=d.__iter__() #字典是可迭代对象
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())

    结果
    a
    b
    c
    迭代器的特点:
    1.提供一种不依赖于索引的求值方法
    2.惰性计算,什么时间用,什么 时间调,节省内存空间
    缺点:
    1.取值麻烦,要依次按照顺序取值
    2.迭代只能往后取,不能向前取
    3.不能获取迭代的长度,
    for i in list: list是经过了两步 1. list__iter__() 结果赋值给 i , #生产迭代器
                       2. i.__next__() 得到list的每个值



    ==============================================================================
    关于函数作业:
    一:编写函数,(函数执行的时间是随机的)

    import random
    import time
    def timmer():
    start_time=time.time()
    time_sleep=random.randrange
    stop_time=time.time()
    res=start_time-stop_time
    return res
    print(res)


    二:编写装饰器,为函数加上统计时间的功能,,# 就是说一个功能在一个时间段内启动到结束的时间,就限定在一个范围,
    import time
    import random

    def timmer(func):
    def wrapper():
    start_time=time.time()
    func()
    stop_time=time.time()
    res=stop_time-start_time
    print('run time is %s ' %(stop_time-start_time))
    return wrapper #不能条括号,加了就是是执行函数,只需要wrapper返回值就可以

    @timmer
    def index():
    time.sleep(random.randrange(1,4))
    print('welcome to index page')
    index()

    --结果
    welcome to index page #index函数功能,
    run time is 3.0003855228424072 #统计出函数运行的时
    四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件)
    ,要求登录成功一次,后续的函数都无需再输入用户名和密码
    注意:从文件中读出字符串形式的字典,
    可以用eval('{"name":"egon","password":"123"}')转成字典格式
    def auth(func):
    def wrapper():
    name=input('name:').strip()
    pwd=input('pwd:').strip()
    filepath=r'C:UserslenovoPycharmProjectsuntitled6.14file1.txt'
    with open(filepath,'rb') as f :
    dic_user=eval(f.read()) #eval把文件转换为字典
    #for i in dic_user:

    if name in dic_user or pwd == dic_user[name] :
    print('ok')
    func()
    else:
    print('err')
    return wrapper

    @auth
    def index() :

    print('welcome to index page')
    index()
    五:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
    from urllib.request import urlopen
    def index(url):
    return urlopen(url).read()

    print(index('https://www.baidu.com/'))

    结果:
    b'<html> <head> <script> location.replace
    (location.href.replace("https://","http://")); </s
    六:为题目五编写装饰器,实现缓存网页内容的功能:
    # 具体:实现下载的页面存放于文件中,如果文件内有值
    # (文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
    from urllib.request import urlopen
    import os
    cache_file=r'C:UserslenovoPycharmProjectsuntitled6.14cache.txt'
    def make_cache(func):
    def wrapper(*args,**kwargs):
    with open(cache_file,'rb') as f :
    if os.path.getsize(cache_file) : #判断文件大小
    res=f.read()
    else:
    res=func(*args,**kwargs) #func()就是get()函数,不管get传入什么,都能接受,
    with open(cache_file,'wb') as f :# 把写的方式打开文件,
    res=f.write(res) #把写的文件返回
    return res
    return wrapper


    @make_cache
    def get(url):
    return urlopen(url).read()
    print(get('http://www.baidu.com'))
    ---结果--- b'<html> <head> <script> location.replace(location.href.replace("https://",........
    cache.TXT文件内容

    ===========
    # 基于上题所讲网页缓存装饰器的基础上,实现缓存不同网页的功能
    # 要求,用户提交的不同url,都能缓存下来,对相同的url发起下载请求,优先从缓存里取内容

    # 分析:
    #1,判断网页是否在有缓存,有缓存,就从文件里读,没有缓存,就下载,
    #2.没有缓存,不同的网页根据他的哈希值来判断,存到哪个文件夹
    未完,待续
    ===========================
    生成器(generator)
    先定义概念,生成器就是迭代器,也有next() 方法,
    函数体内包含yield的关键字,该函数的执行结果就是生成器,
    iteration 迭代器
    generation 生成器
    yield相当于return,一次只能返回一次值,

    为什么要有生成器?

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

    简单生成器

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    >>> L = [x * x for x in range(10)]
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> g = (x * x for x in range(10))
    >>> g
    <generator object <genexpr> at 0x104feab40>

    简单生成器

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    yield相当于把 .__iter__()和 .__next__()为函数封装好
    遵循迭代器的取值方式,obj.__next__(),触发函数的执行,函数的暂停与再继续状态都有yield保存。

    用yield 生成斐波那契数据类型(100内)

    def foo():
      a = b = 1
      yield a
      yield b
      while 1:
        a,b = b,a+b
        yield b
    for num in foo():
      if num > 100:
        break
      print(num)
    foo() #1 1 2 3 5 8 13 21 34 55 89








     
     
     










     
  • 相关阅读:
    ActiveMq主从机制
    Calling handler.OnEndpointsUpdate报错原因
    【Android Studio安装部署系列】二十二、Android studio自动生成set、get方法
    【Android Studio安装部署系列】二十一、Android studio将项目上传到github中
    【Android Studio安装部署系列】二十、Android studio如何将so文件添加到svn中
    【Android Studio安装部署系列】十九、Android studio使用SVN
    【Android Studio安装部署系列】十八、Android studio更换APP应用图标
    【Android Studio安装部署系列】十七、Android studio引用第三方库、jar、so、arr文件
    【Android Studio安装部署系列】十六、Android studio在layout目录下新建子目录
    【Android Studio安装部署系列】十五、Android studio添加Assets目录
  • 原文地址:https://www.cnblogs.com/gyh04541/p/7046112.html
Copyright © 2020-2023  润新知