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

函数的嵌套调用:

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

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)
原文地址:https://www.cnblogs.com/Ryans-World/p/7223624.html