Java教程

py 生成器对象,yield,模块的学习 day 17

本文主要是介绍py 生成器对象,yield,模块的学习 day 17,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

昨日内容回顾

可迭代对象

1.什么是迭代
	迭代就是更新换代,但是每次迭代的过程都需要依赖上一次的结果。最常见的例子就是:游戏的更新
    
2.可迭代对象
	内置有__iter__方法的都可以称之为是可迭代对象
    字符串、列表、字典、元组、集合、文件对象
'''
	1.__iter__类似代码的读法>>>:双下方法
	2.简便方法
	  __iter__  iter()
	  __next__  next()
'''

3.迭代器对象
# 1.迭代器对象的特征
	有__iter__和__next__方法
# 2.如何产生迭代器对象
	可迭代对象调用__iter__方法就会变成迭代器对象
    '''
    迭代器对象如果再次调用__iter__方法还是迭代器对象本身
    '''
# 3.迭代器对象的作用
	能够存储数据并节省存储空间,是一种优化的数据存储形式
# 4.迭代器对象取值的特征
	内部数据每取一次就会少一个,取完了内部数据也就空了(但是是同一个迭代器)
# 5.迭代器对象的主要应用
	提供了一种不依赖与索引取值的方式
    是对无序容器类型进行迭代取值的必要

异常处理

异常处理的语法结构:

try:
    	可能会出错的代码
  except 出错的类型1 as e:
    	针对出错类型的解决措施
  except 出错的类型2 as e:
    	针对出错类型的解决措施 
  except 出错的类型3 as e:
    	针对出错类型的解决措施
  except 万能异常(Exception) as e:
    	统一出错的解决措施
  else:
    	可能会出错的代码没有出错 执行完毕后就会走else
  finally:
    	无论上面怎么走 最后都要走finally

for循环的本质

res = 可迭代对象.__iter__()
while True:
    try:
        print(res.__next__)
    except StopIteration as e:
        break
# 万能异常可以捕获很多常见的异常类型

今日学习

生成器对象(自定义迭代器)

# 本质上还是迭代器,只是通过自己写代码产生的
其中也是包含: __iter__和__next__方法的
例:
def index():
    print('are you kidding me ?')
    yield 123
    yield 123, 111
    print('must be forgot me')
    yield 666
    
'''生成器对象也是节省存储空间的 特性与迭代器对象一致'''
'''
	当函数体代码中含有yield关键字
    第一次调用函数并不会执行函数体代码
    而是将函数变成了生成器
'''

# 没有调用之前,它就是一个普通的函数
print(index)  # <function index at 0x00000269CC501F28>

# 加括号调用并接收结果:不执行代码,而是变成生成器对象(迭代器)
res = index()
print(rse)  
# <generator object index at 0x00000269CC992E08>
# 变成生成器对象之后调用__next__就会开始执行函数体代码
res.__next__()  # are you kidding me ?
print(res.__next__())  
# are you kidding me ?
# 123
print(res.__next__())  # 
# are you kidding me ?
# 123
# (123, 111)
print(res.__next__())
# are you kidding me ?
# 123
# (123, 111)
# must be forgot me
# 666
print(res.__next__())  # 生成器对象内容被取完
# 报错,因为没东西取了
# StopIteration
for i in res:
    print(i)
'''
	如果函数体代码中含有多个yield关键字  执行一次__next__返回后面的值并且让代码停留在yield位置 
	再次执行__next__基于上次的位置继续往后执行到下一个yield关键字处
	如果没有了 再执行也会报错  StopIteration
'''

自定义range方法

# range方法其实是一个可迭代对象
for i in range(1, 10):
    print(i)
问题:通过生成器模拟range方法
def my_range():
    pass
for i in my_range(1, 10):
    print(i)
    
# 首先以两个参数的range方法为例
def my_range(start, end=None, step=1):
    if not end:  # 没有给end传值  my_range(10)
        end = start
        start = 0
'end可以不传值,应该设置成默认参数,end=None'
'将形参进行调换 end = start'
    while start < end:
        yield start
        start += step
'第三个参数step默认值为1'
'每次递增就只用递增step的值就好了 start += step'     

# 先建大框架,然后再考虑参数的情况,整体状态如下
def my_range(start, end=None, step=1):
    if not end:
        end = start
        start = 0
    while start < end:
        yield start
        start += step
for i in my_range(1,10):
    print(i)  
'''
1
2
3
4
5
6
7
8
9
'''

yield关键字的作用

yield关键字有以下的作用:
1.在函数体代码中出现,可以将函数变成生成器
2.在执行的过程中可以将跟在yield后面的值返回出去,类似于return的返回作用
3.而且它还可以暂停住代码的运行
4.最后还有一个接收外界传值的作用

def eat(name):
    print(f'{name}可以吃饭了)
    while True:
          food = yield
          print(f'{name}正在吃什么{food})
res = eat('老赵')
# 想执行一次代码,用双下next方法,如果想多次执行可以用for循环
res.__next__()  # 老赵可以吃饭了
res.__next__()  # 老赵正在吃什么None
res.__next__()  # 老赵正在吃什么None
# 问,现在在food值为None的情况下如何传值呢
'send方法可以给yield传值,而且还能自动调用一次双下next方法'
res.send('蛋糕')  # 老赵正在吃什么蛋糕
res.send('烩面')  # 老赵正在吃什么烩面

生成式表达式

功能:为了节省存储空间
res = (i for i in 'jason')
print(res)  
# <generator object <genexpr> at 0x1130cf468>
print(res.__next__())
'生成器内部的代码只有在调用__next__迭代取值的时候才会执行'

# 普通的求和函数
def add(n, i):
    return n + i
# 再定义一个函数test
def test():
    for i in range(4):
        yield i
# 将test函数变成生成器对象
res = test()
# 一个for循环
for n in (1, 10):
    res = (add(n, i) for i in res)
"""
    第一次for循环
        g = (add(n, i) for i in g)
    第二次for循环
        g = (add(10, i) for i in (add(10, i) for i in g))
"""
res = list(g) # list底层就是for循环,相当于对g做了迭代取值操作
print(res)
res = [20, 21, 22, 23]

模块

'''
import time  # 导入模块
time.time()  # 调用模块内的方法
'''
# 1.什么是模块?
	模块就是某一特定功能方向的方法,可以直接调用使用
# 2.为什么要用模块?
	极大地提升开发效率,可以省去很多时间从而完成需求的功能
# 3.模块的三种来源
	1.内置的模块
  	无需下载,python解释器自带,直接导入使用即可
  2.自定义模块
  	自己写的符合某一功能的代码,封装成模块,自己用或者发布到网上供别人使用
  3.第三方模块
  	别人写的发布到网上的,可以下载使用的模块(很多大佬都是写第三方模块的)
# 4.模块的四种表现形式
  1.使用python代码编写的py文件  # 掌握
  2.多个py文件组成的文件夹(包)  # 掌握
  3.已被编译为共享库或DLL的c或C++扩展(了解)
  4.使用C编写并链接到python解释器的内置模块(了解)

模块的两张导入方式

导入的方法有两种:
# 方式一: import方式...句式
import xxx(你需要导入的模块的名称)
'首先必须明白谁是执行文件谁是被导入文件(模块)'
'''
模块中 .py是执行文件  md.py文件是被导入文件(模块)
模块只需要导入一次即可,不需要重复导入
'''
然而导入模块的内部发生了什么事呢?
	1.执行当前文件 产生一个当前文件的名称空间
    2.执行import句式 导入模块文件(即执行模块文件代码产生模块文件的名称空间)
    3.在当前文件的名称空间中产生一个模块的名字 指向模块的名称空间 
    4.通过该名字就可以使用到模块名称空间中的所有数据
ps:相同的模块反复被导入只会执行一次
    
print(md.name)  # 获取模块名称空间中的name
print(name)  # 获取当前名称空间中的name

import md
money = 666
md.change()
print(money)

# 方式二: from...import...句式
from md import name,money,read1
print(name)  # jasonNB
name = 'kevin'
print(name)  # kevin

print(money)  # 报错  from md import name 只使用模块中的name名字
read1()
'''
执行当前文件产生一个名称空间
执行导入语句,运行模块文件产生名称空间存放运行过程中的所有名称
将import后面的名字直接拿到当前执行文件中
'''

# 注意
1.模块即使重复导入也只能导入一次
2.模块空间名称空间中的名字不需要加模块名前缀,大可直接使用
3.但是from...import的句式会产生名字冲突的问题,所以使用的时候要注意
4.使用from...import的句式,只能使用import后面出现的名字

导入模块的补充

1.模块可以取别名,也就是简写(在使用率的情况下)
import md as m
print(m.name)
from md import name as n
print(n)

2.连续导入多个模块或者变量名
import time, sys, md
from md import name, read1, read2
"""
	连续导入多个模块,这多个模块最好有相似的功能部分,如果没有建议分开导入
    如果是同一个模块下的多个变量名则影响较小
"""
import time
import sys
import md

3.通用导入
from md import *
'''
* 代表导入模块md中的所有变量名字,from...import的句式也可以导入所有的名字
'''
如果模块文件中使用了双下all限制可以使用的名字,那么*号就会失效,依据双下all后面列举的名字

今日的两种模块导入方式的内部内部图

今天主要学习了模块的一些使用及方法,受益颇深,原来导入模块也有这么多讲究,着实要好好想想思考思考

这篇关于py 生成器对象,yield,模块的学习 day 17的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!