• 嵌套,名称空间,闭包,装饰器,迭代器,生成器,三元表达式,列表解析


    函数的嵌套调用:

    在调用一个函数的过程中,又调用了其他函数

    def bar():
        print('from bar')
     
    def foo():
        print('from foo')
        bar()
     
    foo()

    函数的嵌套定义:

    在一个函数的内部,又定义了另外一个函数

    在函数内部定义的名字,只能在内部使用,在外部无法使用

    def f1():
        x = 1
        def f2():
            print('from f2')
            print(x)     #打印值
            print(f2)    #打印内存地址
        f2()
    
    f1()

    名称空间:

    存放名字的地方,准确的说是存放名字与变量值绑定关系的地方

    又可分为:内置名称空间,全局名称空间,局部名称空间

    内置名称空间:

    在python解释器启动时产生,存放一些python内置的名字,例如 len(),if

    内置名称空间会存在于整个程序运行的始终

    全局名称空间:

    在执行文件时产生,存放文件级别定义的名字,在文件执行结束后失效,除非中途进行了

    例如del x等的命令,x会失效。

    x=1
    def func():
        pass
    import os
    class Foo:
        pass
    if x==1:z=3

    局部名称空间:

    在执行文件的过程中,如果调用了该函数,则会产生该函数的局部名称空间,

    用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束时失效

    三个名称空间的加载顺序:

    内置名称空间-->全局名称空间-->局部名称空间

    名字的查找顺序:

    局部名称空间-->全局名称空间-->内置名称空间

    站在局部找max的值

    max=1
    def foo():
        max=2
        print(max)
    
    foo()  # max=2
    max=1
    def foo():
        print(max)
     
    foo()  # max=1
    def foo():
        print(max)
     
    foo()  # <built-in function max>  # max()是内置函数,max是内置的函数名

    站在全局找max的值

    max=1
    def foo():
      max=2
    
    foo()
    print(max)  # 1
    def foo():
      max=2
    
    foo()
    print(max)  # <built-in function max>

    作用域:

    作用的范围

    全局作用域:全局存活,全局有效,内置名称空间和全局名称空间的作用域一直到程序结束

    局部作用域:临时存活,局部有效

    查看全局作用域有哪些名字---->globals()

    查看局部作用域有哪些名字---->locals()

    x=111111

    def
    f1(): x=1 y=2 def f2():pass print(locals()) print(globals()) f1()
    #运行结果
    {'f2': <function f1.<locals>.f2 at 0x000001B98D58EF28>, 'y': 2, 'x': 1}
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001B98D4B9748>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/PyCharm_Projects/day5/a.py', '__cached__': None, 'x': 111111, 'f1': <function f1 at 0x000001B98D3C3E18>}

    global关键字和nonlocal关键字:

    个人认为global稍微有点儿用,nonlocal在实际应用中并没有什么卵用

    x=1
    def f1():
        x=2
    f1()
    print(x)  # x=1
    x=1
    def f1():
        global x   # 避免在局部修改全局的名字,所以global 不推荐使用
        x=2
    f1()
    print(x)  # x=2
    l=[]
    def f2():
        l.append('f2')
    f2()
    print(l)    # ['f2'],为什么不加global就直接能改呢?因为l本身就是可变类型,上面的x是不可变类型,但无论是global还是现在的l.append()方式,都应该避免,函数的执行不要对全局产生影响
    x=0
    def f1():
        x=1
        def f2():
            x=2
            def f3():
                global x    #这是修改全局,所以最后x=3,但如果想改上面的x=2,该如何修改呢?
                x=3
            f3()
        f2()
    f1()
    print(x)  
    x=0
    def f1():
        x=1
        def f2():
                x=2
                def f3():
                    nonlocal x   #修改函数内部正上方的x,跳出当前这一层,并且只在函数内部有效
                    x=3
                f3()
                print(x)     #这里原本是输出2(注释nonlocal x试试),但因为nonlocal x的原因,上层的x=2被更改为x=3
        f2()
    f1()     # x=3
    x=0
    def f1():
        x=1
        def f2():
                # x=2
                def f3():
                    nonlocal x   #修改函数内部正上方的x,跳出当前这一层,并且只在函数内部有效
                    x=3
                f3()
                # print(x)     
        f2()
        print(x)     #同样,注释上面的print(x),就把x=1改为了x=3
    f1()    # x=3
    x=0
    def f1():
        # x=1
        def f2():
                # x=2
                def f3():
                    nonlocal x   
                    x=3
                f3()
                # print(x)     
        f2()
        # print(x)
    f1()  #报错,因为nonlocal只能应用在局部使用,要想改全局,使用global

     作用域关系在函数定义时就已经固定,与调用位置无关

    x=1
    def f1():
        def f2():
            print(x)
        f2()        #f2受层级的限制,只能在这里调用
    f1()
    
    print(f1())
    x=1
    def f1():
        def f2():
            print(x)
        return f2       #有了函数对象的概念后,就可以把函数返回出来,打破层级的限制,在任意位置调用
    
    func=f1()    #在全局定义了func,指向了局部定义的f2的内存地址
    print(func)
    x=1
    def f1():
        def f2():
            print(x)
        return f2
    
    func=f1()  #找到了全局x,全局的x可能被改掉
    x=1000    #在这里全局的x已经被改掉了,不是x=1了,
    func()    # x=1000 。 调用func()在更改x之后发生的,所以这里访问的x仍然是全局的x,但全局的x已经被改了
    x=1000    #x=1
    x=1
    def f1():
        def f2():
            print(x)
        return f2
    
    def foo(func):
        x=3000
        func()   #func=f2,那么此时x=???,  x=1,为什么?因为作用域关系,在函数定义时就已经固定,与调用位置无关
                 #所以这里的fun()是调用,仍然要回到最原来的定义位置找作用域关系,最原来的位置在
                 # def f2():
                 #     print(x)   这里的x访问的就是全局的x
    foo(f1())   #f1()的结果是f2的内存地址
    x=1
    def f1():
        def f2():
            print(x)
        return f2
    
    x=1000
    def foo(func):
        x=3000
        func()
    
    foo(f1())   # x=1000,调用之前已经被改过了
    x=1
    def f1():
        def f2():
            print(x)
        return f2
    
    
    def foo(func):
        x=3000
        func()
    
    foo(f1())   # 那么此时x=?,  x=1
    x=1000      #调用完了以后,又修改了全局的x
    foo(f1())   #x=1000

    闭包:

    定义在函数内部的函数,包含对外部作用域名字的引用,而不是对全局作用域名字的引用,那么该内部函数就称为闭包函数

    x=1                          #非此全局作用域
    def f1():
        x=1111                   #包含对外部作用域名字的引用,而不是全局作用域名字的引用,若注释 x=1111,就引用全局作用域了,就不是闭包函数了
        def f2():                #定义在函数内部的函数
            print(x)
        return f2   #f2是闭包函数
    
    func=f1()      #这里不仅拿到了f2,还拿到了x=1111
    func()
    x=1
    def f1():
        x=1111
        def f2():
            print(x)
        return f2
    
    func=f1()
    
    x=100
    func()   # x=1111
    x=1
    def f1():
        x=1111
        def f2():
            print(x)
        return f2
    
    func=f1()   
    
    def foo():
        x=2222
        func()   # 不管func放到哪里去运行,都以我自己外面包的那个值为准,都以x=1111为准,相当于f2()捆绑了x=1111
    foo()    # x=1111

    给函数传参的一种方式--->闭包函数

    def deco():
        x=123
        def wrapper():
            print(x)
        return wrapper
    
    func=deco()

    闭包函数的应用--->惰性计算

    传参的方式

    import requests
    
    def get(url):
        return requests.get(url).txt
    
    print(get('https://www.python.org'))

    闭包的方式,不用传参,自己本身就包含了状态

    import requests
    
    def index():
        url='https://www.python.org'
        def get():
            return requests.get(url).text
        return get
    
    python_web=index()

    python_web()

    但这个函数已经被写死了,如果是要爬取其它的网站呢?

    import requests
    
    def index(url):    #url从这个位置传进来,其实就相当于在内部定义了 url=*********,
    # url=*********
    def get(): return requests.get(url).text return get python_web=index('https://www.python.org') # 从此位置传入 baidu_web=index('https://www.baidu.com') python_web() #python_web拿到了get函数,而且还包括url地址,如index('https://www.python.org') baidu_web() #baidu_web拿到了get函数,而且还包括url地址,如index('https://www.baidu.com')

    那么和默认参数有什么区别呢?

    默认参数都有一个唯一的值

    import requests
    def get(url='https://www.python.org'):
        print(requests.get(url).text)
        
    get()

    好像也没什么问题,但如果爬取百度呢

    import requests
    def get(url='https://www.python.org'):
        print(requests.get(url).text)
    
    get()
    
    get('https://www.baidu.com')

    需要重新传'https://www.baidu.com',而闭包是什么?是在调用的时候就已经把地址附加给get函数了,所以

    python_web拿到的get函数,就已经携带了url地址的get函数,这样每一个函数都包含了自己的一个状态,

    默认函数解决不了目前的问题。

    装饰器:

    为什么用装饰器?

    1.开放封闭原则:对扩展是开放的,对修改是封闭的

    2.装饰器:为其它添加新功能

    装饰器本身可以是可调用对象,被装饰的对象本身也可以是任意可调用对象

    装饰器遵循的原则:

    1.不修改被装饰对象的源代码

    2.不修改被调用对象的调用方式

    装饰器的目的:

    在遵循原则1和2的前提下,为其它函数添加新功能

    一个简单的函数如下

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

    那么现在统计一下这个函数的运行时间

    import time
    
    def index():
        start=time.time()
        time.sleep(3)
        print('welcome to index')
        stop=time.time()
        print('run time is %s' %(stop-start))
    
    index()

    # welcome to index
    # run time is 3.0003116130828857

    犯了一个错误,直接修改了源代码

    import time
    
    def index():
        time.sleep(3)
        print('welcome to index')
    
    def wrapper(func):
        start=time.time()
        func()
        stop=time.time()
        print('run time is %s' % (stop-start))
    
    wrapper(index)

    # welcome to index
    # run time is 3.007117509841919

    运行了,并且加上了新功能,没有更改源代码,但是调用方式更改了,原先是index(),现在是wrapper(index)

    装饰器其实就是闭包函数的应用

    import time
    
    def index():
        time.sleep(3)
        print('welcome to index')
    
    def timmer():
        func=index
        def wrapper():
            start=time.time()
            func()
            stop=time.time()
            print('run time is %s' % (stop-start))
        return wrapper
    
    index=timmer()
    index()

    但是如果再加一个home()函数呢?怎么加到上面的代码里面使其具备通用性呢?

    def home():
        time.sleep(2)
        print('welcome to home page')

    改为如下:

    import time
    
    def index():
        time.sleep(3)
        print('welcome to index')
    
    def home():
        time.sleep(2)
        print('welcome to home page')
    
    def timmer(func):
        # func=index
        def wrapper():
            start=time.time()
            func()
            stop=time.time()
            print('run time is %s' % (stop-start))
        return wrapper
    
    index=timmer(index)
    home=timmer(home)
    
    index()
    home()

    Python提供了简洁的语法

    import time
    
    def timmer(func):    
        # func=index
        def wrapper():
            start=time.time()
            func()
            stop=time.time()
            print('run time is %s' % (stop-start))
        return wrapper
    
    @timmer    #index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
    
    @timmer    #home=timmer(home)
    def home():
        time.sleep(2)
        print('welcome to home page')
    
    index()
    home()

    被装饰的对象有什么特点?都是无参函数,但如果是传入参数呢?

    @timmer    #home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page'% name)
    home('egon')   # 报错 wrapper() takes 0positional arguments but 1 was given

    home('egon')  相当于wrapper('egon'),但是def wrapper():...   定义时,不需要传参数,所以报错

    如何解决?

    import time
    
    def timmer(func):
        # func=index
        def wrapper(name):    # name变量是给func用的,所以也需要给func传入name
            start=time.time()
            func(name)
            stop=time.time()
            print('run time is %s' % (stop-start))
        return wrapper
    
    # @timmer    #index=timmer(index)
    # def index():
    #     time.sleep(3)
    #     print('welcome to index')
    
    @timmer    #home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page'% name)
    
    # index()
    home('egon')

    # welcome egon to home page
    # run time is 2.000490427017212

    但是index()呢?所以装饰器里面的闭包函数要能适应无参和有参,并且能适应各种形式的传参方式

    import time
    
    def timmer(func):
        # func=index
        def wrapper(*args,**kwargs):      #仅更改此部分即可
            start=time.time()
            func(*args,**kwargs)          #
            stop=time.time()
            print('run time is %s' % (stop-start))
        return wrapper
    
    @timmer    #index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
    
    @timmer    #home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page'% name)
    
    index()
    home('egon')

    目前的情况是index()函数和home()函数都没有返回值,但若给index()函数增加一个返回值呢?

    import time
    
    def timmer(func):
        # func=index
        def wrapper(*args,**kwargs):
            start=time.time()
            func(*args,**kwargs)
            stop=time.time()
            print('run time is %s' % (stop-start))
        return wrapper
    
    @timmer    #index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
        return 123
    
    @timmer    #home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page'% name)
    
    res=index()                           # res=wrapper()
    print(res)
    # home('egon')

    # welcome to index
    # run time is 3.0002543926239014
    # None 现在index已经不是最原始的index函数了,这里调用的是wrapper函数,所以这里拿到的是wrapper函数的返回值,但是wrapper函数没有返回值

    解决返回值的问题

    import time
    
    def timmer(func):
        # func=index
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)    #func函数的返回值
            stop=time.time()
            print('run time is %s' % (stop-start))
            return res                #返回函数的原始函数的返回值
        return wrapper
    
    @timmer    #index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
        return 123
    
    @timmer    #home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page'% name)
    
    res=index()
    print(res)
    
    res1=home('egon')
    print(res1)

    实现认证功能的装饰器

    def timmer(func):                  #基本的装饰器形式,基于这种形式可以玩出很多样式
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)   # func是最原始的函数,想统计时间,上下加时间就好了,想执行认证功能,前面加用户名,密码和if判断即可
            return res
        return wrapper
    def auth(func):
        def wrapper(*args, **kwargs):
            name=input('name: ').strip()
            password=input('password: ').strip()
            if name == 'johnny' and password == '3714':
                res = func(*args, **kwargs)
                return res
            else:
                print('user or password error')
        return wrapper
    
    @auth  # index=auth(index)
    def index():
        print('from index')
    
    index()  # 实际上执行的是wrapper()

    目前是把用户名和密码写死了,那么改为用文件的形式存储用户名和密码

    {'alex':'alex3714','egon':'123','wu':'456','johnny':'789'}        # db.txt
    def auth(func):
        def wrapper(*args, **kwargs):
            name=input('name: ').strip()
            password=input('password: ').strip()
            with open('db.txt',encoding='utf-8') as f:
                user_dic = eval(f.read())  #文件中的内容都是字符串的形式
            if name in user_dic and password == user_dic[name]:
                res = func(*args,**kwargs)
                return res
            else:
                print('user or password error')
        return wrapper
    
    @auth  # index=auth(index)
    def index():
        print('from index')
    
    index()  # 实际上执行的是wrapper()
    current_user={'user':None}    #用来记住用户的状态,默认是没有登陆的
    
    def auth(func):
        def wrapper(*args, **kwargs):
            if current_user['user']:              #如果账号已经登陆了,记录了状态,就不需要再输入用户名和密码了
                return func(*args,**kwargs)
            name=input('name: ').strip()
            password=input('password: ').strip()
            with open('db.txt',encoding='utf-8') as f:
                user_dic = eval(f.read())  #文件中的内容都是字符串的形式
            if name in user_dic and password == user_dic[name]:
                res = func(*args,**kwargs)
                current_user['user'] =name       # 账户登录后就记住用户的登录状态
                return res
            else:
                print('user or password error')
        return wrapper
    
    @auth  # index=auth(index)
    def index():
        print('from index')
    
    @auth
    def home(name):                              #再增加一个函数
        print('welcome %s'% name)
    
    index()  # 实际上执行的是wrapper()
    home('johnny')

    以上部分为无参装饰器

    以下部分为有参装饰器

    若有多种认证类型,该如何解决呢?

    current_user={'user':None}
    
    def auth(auth_type = 'file'):
        def deco(func):
            def wrapper(*args, **kwargs):
                if auth_type == 'file':
                    if current_user['user']:
                        return func(*args,**kwargs)
                    name=input('name: ').strip()
                    password=input('password: ').strip()
                    with open('db.txt',encoding='utf-8') as f:
                        user_dic = eval(f.read())
                    if name in user_dic and password == user_dic[name]:
                        res = func(*args,**kwargs)
                        current_user['user'] =name
                        return res
                    else:
                        print('user or password error')
                elif auth_type == 'mysql':
                    print('mysql')
                elif auth_type == 'ldap':
                    print('ldap')
                else:
                    print('invalid auth_type')
            return wrapper
        return deco
    
    @auth(auth_type='mysql')   # @deco  ----> # index=deco(index)   index拿到的仍然是wrapper函数,没有变
    def index():
        print('from index')

    @auth(auth_type='file')
    def home():
    print('welcome %s' %name)
    index()
    # wrapper()
    home('egon')

    # mysql
    # name: egon
    # password: 123
    # user or password error

    闭包函数用到三层就已经能满足需求了,因为,最外层已经可以任意传参数了,里面的函数就可以从最外层得到参数

    补充:

    1.注释信息

    import time
    from functools import wraps      ####
    
    def timmer(func):
        @wraps(func)                 #####
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)
            stop=time.time()
            print('run time is %s' %(stop-start))
            return res
        return wrapper
    
    @timmer    #index=timmer(index)
    def index():
        '''这是index函数'''
        time.sleep(3)
        print('welcome to index')
        return 123
    
    print(index.__doc__)      # 如果不加上面后面加####的两行,打印出的注释信息就会显示 None

    2.一个函数上面可以有多个装饰器

    import time
    from functools import wraps     ####
    current_user={'user':None}
    
    def timmer(func):
        @wraps(func)                 #####
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)
            stop=time.time()
            print('run time is %s' %(stop-start))
            return res
        return wrapper
    
    def auth(auth_type = 'file'):
        def deco(func):
            def wrapper(*args, **kwargs):
                if auth_type == 'file':
                    if current_user['user']:
                        return func(*args,**kwargs)
                    name=input('name: ').strip()
                    password=input('password: ').strip()
                    with open('db.txt',encoding='utf-8') as f:
                        user_dic = eval(f.read())
                    if name in user_dic and password == user_dic[name]:
                        res = func(*args,**kwargs)
                        current_user['user'] =name
                        return res
                    else:
                        print('user or password error')
                elif auth_type == 'mysql':
                    print('mysql')
                elif auth_type == 'ldap':
                    print('ldap')
                else:
                    print('invalid auth_type')
            return wrapper
        return deco
    
    @timmer    #index=timmer(index)
    @auth()    # @deco  # index=deco(index) #wrapper
    def index():
        '''这是index函数'''
        time.sleep(3)
        print('welcome to index')
        return 123
    
    # print(index.__doc__)
    index()
    
    # name: egon
    # password: 123
    # user or password error
    # run time is 4.882465362548828

    但如果颠倒@timmer和@auth的顺序,则结果会是

    # name: alex
    # password: alex3714
    # welcome to index
    # run time is 3.0001471042633057

    迭代器

    迭代:是一个重复的过程,每一次重复,都是基于上一次结果而来

    先不用for
    l=['a','b','c','d']
    count=0
    while count < len(l):
        print(l[count])
        count +=1

    重复的过程,每一次的结果都是基于上一次的结果而来的,所以上面就是迭代。取出序列里面的元素就是迭代

    什么是序列类型?有顺序的类型,字符串,列表,元祖,但字典不是,所以通过索引的方式只能从序列类型中取数值,那如何从没有索引的类型中取数值呢?比如字典

    dic={'name':'johnny','sex':'m','age':'10'}

    没有for,for是接下来要写的内容,while能做到吗?while依赖于索引的方式迭代取值的,所以只适用于字符串,列表,元祖,但是对于文件,集合,字典,他们都没有索引,但有这种通过迭代把值取出来的需求。所以必须有一种方式不依赖于索引,这样才能取出字典,文件,集合中的值。Python提供的这种方式就是迭代器

    迭代器:提供一种不依赖于索引的取值方式,让迭代非序列类型变为可能

    首先什么是可迭代对象(iterable)?

    凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象

    dic={'name':'johnny','sex':'m','age':'10'}
    
    i=dic.__iter__()
    print(i)    # iterator对象
    
    # <dict_keyiterator object at 0x000001D8A9E703B8>

    然后有__iter__这个方法,执行一下,执行后的结果就是迭代器对象(iterator),那么有什么用呢?

    要解决从字典里面取值,并且不依赖于索引

    # i.__next__()      # next(i)
    print(next(i))
    print(next(i))
    print(next(i))

    # name
    # sex
    # age

    把字典的key都取出来了,并且没有依赖索引

    但若再执行print(next(i)),就会有 StopIteration 的错误信息

    l=['a','b','c','d']
    # l 没有__next__方法,只有执行了__iter__方法后的结果才有__next__方法
    i
    =l.__iter__() print(i) # <list_iterator object at 0x000001EA01ABD5C0>
    i1=i.__iter__()
    print(i1) # <list_iterator object at 0x000001EA01ABD5C0>
    所以,迭代器也有__iter__方法,返回的就是本身,并且也是可迭代的对象,有__next__方法
    print(next(i)) #a
    print(next(i)) #b
    print(next(i)) #c
    print(next(i)) #d
    print(next(i)) # StopIteration
    # 没有按照索引取值
    l=['a','b','c','d']
    
    iter_l=iter(l)
    while True:
        try:
            print(next(iter_l))
        except StopIteration:
            break
            
    # a
    # b
    # c
    # d
    dic={'name':'johnny','sex':'m','age':'10'}
    
    iter_dic=iter(dic)
    while True:
        try:
            k=next(iter_dic)
            print(k,dic[k])
        except StopIteration:
            break
    
    # name johnny
    # sex m
    # age 10

    迭代器对象的优点:

    1.提供了一种统一的(不依赖于索引的)迭代方式

    2.迭代器本身比其他数据类型更省内存

    迭代器缺点

    1.一次性的,只能往后next,不能回退,不如索引取值灵活

    2.无法预知什么时候取值结束,即无法预知长度

    for循环的原理

    l=['a','b','c','d']
    for item in l:    # iter_l=l.__iter__()
        print(item)

    for循环就是在用迭代器,for循环先调用这个序列的__iter__方法,所以for只能应用于可迭代的对象,拿到

    iter_l这个迭代器后就是用这个迭代器,for循环调用next方法,赋值给item,进行一次循环,一直取到报异常,但不会抛出异常,会使用try,except捕捉到这个异常,结束掉这个循环。

    while可不可以实现使用迭代器来循环?但实现起来非常笨拙,自己调用iter方法,变成迭代器,for循环自动做了,并且使用while要自己捕捉异常,for循环也自动做了,所以要迭代一个类型里面的元素,用for循环更合适。

    dic={'name':'johnny','sex':'m','age':'10'}
    
    iter_dic=iter(dic)
    while True:
        try:
            k=next(iter_dic)
            print(k,dic[k])
        except StopIteration:
            break

    迭代器对象为什么也有iter方法?给for循环准备的。

    判断可迭代对象与迭代器对象:

    from collections import Iterable,Iterator
    
    s='hello'
    l=['a','b','c','d']
    t=('a','b','c','d')
    dic={'name':'johnny','sex':'m','age':18}
    set1={1,2,3}
    f=open('db.txt')
    
    print(isinstance(s,Iterable))
    print(isinstance(l,Iterable))
    print(isinstance(t,Iterable))
    print(isinstance(dic,Iterable))
    print(isinstance(set1,Iterable))
    print(isinstance(f,Iterable))
    
    # True
    # True
    # True
    # True
    # True
    # True
    
    print(isinstance(s,Iterator))
    print(isinstance(l,Iterator))
    print(isinstance(t,Iterator))
    print(isinstance(dic,Iterator))
    print(isinstance(set1,Iterator))
    print(isinstance(f,Iterator))
    
    #False
    #False
    #False
    #False
    #False
    #True     只有文件是迭代器对象

    生成器:

    在函数内部包含yield关键字,那么该函数执行的结果就是生成器

    def func():
        print('first')
        yield 1111
        print('second')
        yield 2222
        print('third')
        yield 3333
    
    func()

    执行此段代码并没有什么输出

    def func():
        print('first')
        yield 1111
        print('second')
        yield 2222
        print('third')
        yield 3333
    
    g=func()
    print(g)
    # <generator object func at 0x00000254685A2F10>
    def func():
        print('first')
        yield 1111
        print('second')
        yield 2222
        print('third')
        yield 3333
    print('fourth') g=func()
    print(next(g))
    #first print('===>')
    print(next(g)) #second
    print('===>') print(next(g)) #third

    #first
    #1111
    #===>
    #second
    #2222
    #===>
    #third
    #3333
    def func():
        print('first')
        yield 1111
        print('second')
        yield 2222
        print('third')
        yield 3333
        print('fourth')
    
    g=func()
    
    for i in g:
        print(i)
    
    #first
    #1111
    #second
    #2222
    #third
    #3333
    #fourth

    yield的功能:

    1.把函数的结果做成迭代器(以一种优雅的方式封装好__iter__,__next__)

    def func(n):while True:
    yield n n
    +=1
    g=func(0)
    for i in g:
    print(I)

    因为同一时间在内存中只有一个值,所以不会撑爆内存

    python3中的range(),也是一个生成器,但是python2不是

    现在模拟range()函数

    def my_range(start,stop):
        while True:
            if start == stop:
                raise StopIteration
            yield start
            start +=1
    
    g=my_range(1,3)
    
    print(next(g))
    print(next(g))
    print(next(g))
    def my_range(start,stop):
        while True:
            if start == stop:
                raise StopIteration
            yield start
            start +=1
    
    for i in range(1,5):
        print(i)
    
    #1
    #2
    #3
    #4

    2.return只能返回一次值,而yield可以返回多次值。函数的暂停和再继续运行的状态是由yield完成的

    如何实现linux的tail的功能?

    # python3 tail.py -f access.log | grep 'error'  (管道解决不同进程之间互相传递数据的问题)

    可以使用yield实现管道的功能,利用yield返回多次值的功能

    import time
    
    def tail(file_path):
        with open(file_path,'r') 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:
            if pattern in line:
                print(line,end='')
    
    grep('error',tail('access.log'))
    ---------------------------------------------------
    #追加内容.py
    with open('access.log','a') as f:        此文件用来向access.log文件追加内容
    f.write('2222error ')

    三元表达式:

    def foo(x):
        if x>y:
            return 'ok'
        else:
            return 'no'

    等同于

    x=10
    res='ok' if x > 3 else 'no'
    print(res)
    def max2(x,y):
        return x if x > y else y

    print(max2(1,3))

    列表解析:

    l=[]
    for i in range(10):
    if i >=5: l.append(
    'egg%s' % i) print(l)

    等同于

    l=['egg%s' %i for i in range(10) if i >=5]
    print(l)
    nums=[1,2,3,4,5,6]
    nums_new=[item**2 for item in nums if item > 3]
    print(nums_new)
    names=['tom_ab','jerry_ab','henry_','peter_bc']
    names_new=[name for name in names if name.endswith('ab')]
    print(names_new)

    # ['tom_ab', 'jerry_ab']

    生成器表达式:

    用在数据量非常大的场景

    l=('egg%s' %I for i in range(1000))
    print(l)  # <generator object <genexpr> at 0x00000232729C2F10>
    print(next(l))
    with open('a.txt',encoding='utf-8') as f:    #a.txt存放的数据量很大
        print(max(len(line) for line in f))  #python提供的简写的方式,而不用max((len(line) for line in f))
    with open('a.txt',encoding='utf-8') as f:
        g=(len(line) for line in f)
        print(max(g))
    #db.txt
    apple 10 3
    tesla 10000 1
    mac 3000 2
    Lenovo 3000 3
    chicken 10 3
    with open('db.txt',encoding='utf-8') as f:
        l=[]
        for line in f:
            goods=line.split()
            price=float(goods[1])
            count=int(goods[2])
            cost=price * count
            l.append(cost)
        
        print(sum(l))

    等同于

    with open('db.txt',encoding='utf-8') as f:
        l=(float(line.split()[1])*int(line.split)[2] for line in f)
        print(sum(l))
    with open('db.txt',encoding='utf-8') as f:
        info=[{'name':line.split()[0],'price':float(line.split()[1]),'count':int(line.split()[2])} for line in f if float(line.split()[1])>=30000]
        print(info)
  • 相关阅读:
    Sublime 设置移动光标快捷键
    Reverse Linked List II
    Reverse Nodes in K-Group
    Sort Colors
    Swap Nodes in Pairs
    Intersection of Two Linked Lists
    Word Break
    Unique Binary Search Tree
    Maximal Square
    Happy Number
  • 原文地址:https://www.cnblogs.com/Ryans-World/p/7223624.html
Copyright © 2020-2023  润新知