day03.24

生成器

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

若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象。

生成器的本质还是一个迭代器,只不过是我们自己写的自定义函数代码。生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器,也可以叫自定义迭代器。

生成器对象也是节省存储空间的;特性与迭代器对象一致。生成器与迭代器的最重要的区别就是有没有yield关键字。

当函数体代码中含有yield关键字,第一次调用函数并不会执行函数体代码,而是将函数变成了生成器。

复制代码
def index():
    print('你还记得我吗?')
    yield 123
    yield 123, 111
    print('是不是忘记我了!!!')
    yield 666
print(index)    # <function index at 0x1096c0ea0> 没有调用之前 就是一个普通的函数
res = index()    # 加括号调用并接收结果:不执行代码,而是变成生成器对象(迭代器)
print(res)  # <generator object index at 0x11da33468>
print(res.__next__())  # 123  变成生成器对象之后调用__next__就会开始执行函数体代码,yield有点像return的功能
print(res.__next__())  # (123, 111)  开始下一次yield执行程序,yield有点像return的功能
print(res.__next__())  # 666
print(res.__next__())  # 报错    # 程序执行完毕再次取值会报错
复制代码

ps:

当函数体代码中含有yield关键字时,第一次调用函数并不会执行函数体代码,而是将函数变成了生成器。

如果函数体代码中含有多个yield关键字,执行一次__next__返回后面的值,并且让代码停留在yield位置;

再次执行__next__基于上次的位置继续往后执行到下一个yield关键字处,如果没有了,继续再执行也会报错。

自定义range方法

range方法其实是一个可迭代对象。

复制代码
# 通过生成器模拟range方法
def my_range(start, end=None, step=1):
    if not end:  # 没有给end传值  my_range(10)
        end = start
        start = 0
    while start < end:
        yield start
        start += step


for i in my_range(1, 100):
    print(i)
复制代码

yield关键字

  1. 在函数体代码中出现 可以将函数变成生成器
  2. 在执行过程中 可以将后面的值返回出去 类似于return
  3. 还可以暂停住代码的运行
  4. 还可以接收外界的传值(了解)
复制代码
def eat(name):
    print(f'{name}准备干饭')
    while True:
        food = yield
        print(f'{name}正在吃{food}')


res = eat('赵公子')
# 想执行一次代码  如果想执行多次直至结束 可以直接用for循环
res.__next__()
res.__next__()  # 赵公子正在吃None
res.__next__()  # 赵公子正在吃None
res.send('生日蛋糕')  # 可以给yield传值 并且自动调用一次__next__方法
res.send('大鸡腿')  # 可以给yield传值 并且自动调用一次__next__方法
复制代码

生成器表达式

复制代码
# 生成器对象也是为了节省存储空间,在后期我们做代码优化的时候,可以考虑使用
res = (i for i in 'jason')
print(res)  # <generator object <genexpr> at 0x1130cf468>
print(res.__next__())
"""生成器内部的代码只有在调用__next__迭代取值的时候才会执行"""


# 普通的求和函数
def add(n, i):
    return n + i


# 生成器对象 返回 0 1 2 3
def test():
    for i in range(4):
        yield i


# 将test函数变成生成器对象
g = test()
复制代码

模块

什么是模块?

模块就是一系列功能的结合体,可以直接使用。

eg:import.time    导入模块       

        time.time()    调用模块  

为什么要使用模块?

模块能够极大的提升开发效率!!!

将程序模块化会使得程序的组织结构清晰,维护起来更加方便;程序中的模块可以被重复使用,使用模块既保证了代码的重用性,又增强了程序的结构性和可维护性。

在Python中,一个py文件就是一个模块,文件名为xxx.py模块名则是xxx,导入模块可以引用模块中已经写好的功能。

模块的三种来源

  • 内置的模块

内置模块是解释器自带的模块,无需下载,使用时直接导入使用即可

  • 自定义模块

自定义模块就是指自己写的代码,然后封装成模块,自己用或者发布到网上供别人使用

  • 第三方模块

别人写的发布到网上的程序模块,是可以下载使用的模块

模块的四种表现形式

  1. 使用python代码编写的py文件 
  2. 多个py文件组成的文件夹(包) 
  3. 已被编译为共享库或DLL的c或C++扩展(了解)
  4. 使用C语言编写并链接到python解释器的内置模块(了解)

模块的两种导入方式

模块想要使用,必须要提前导入,只有先导入才能使用。

import...句式

impord md格式

# 运行执行文件,产生一个当前文件的名称空间
import md    # 执行import句式,导入模块文件(即执行模块文件代码产生模块文件的名称空间)
print(md.name)    # 在当前文件的名称空间中产生一个模块的名字,指向模块的名称空间;通过该名字就可以使用到模块名称空间中的所有数据
md.read1()    # 找到模块文件当中的read1()

ps:相同的模块被重复导入只会执行一次!!!

import md    # 有效
import md    # 无效(写了跟没写一样)
import md    # 无效(写了跟没写一样)

import句式的特点:

可以通过import后面的模块名点加变量名的方式,使用模块中所有的名字,并且不会与当前名称空间中的名字冲突。即导入模块当中的变量名可以和当前执行文件当中的变量名相同。

 

from...import...句式

from md import name格式

# 运行执行py文件当中的程序代码,产生一个名称空间
from md import name    # 导入模块当中的一个name变量名,执行导入语句,运行模块文件产生名称空间存放运行过程中的所有名字,将import后面的名字直接拿到当前执行文件中
print(name)  # jasonNB    # 查找模块当中的变量名name所指代的具体内容
name = 'kevin'
print(name)  # kevin    # py文件当中的变量名称name
print(money)    # 报错  只能使用模块当中的name

ps:此句式下重复导入也只会导入运行一次,重复导入会作废。

from...import句式的特点:

  • 使用from...import的句式,只能调用import后面出现的名字
  • 使用模块名称空间中的名字不需要加模块名前缀,直接使用即可
  • 使用from...import的句式会产生名字冲突的问题,在使用的时候一定要避免名字冲突

导入模块句式的补充

  • 可以给模块起别名(使用频率很高)
import md as m
print(m.name)
from md import name as n    # 变量名复杂,可以简写
print(n)

 

  • 可以连续导入多个模块或者变量名
import time, sys, md
from md import name, read1, read2

'''
连续导入多个模块 这多个模块最好有相似的功能部分 如果没有建议分开导入
如果是同一个模块下的多个变量名无所谓!!!
'''

 

  • 通用导入from md import *

*表示md里面所有的名字;

如果模块文件中使用了__all__限制可以使用的名字,那么*号就会失效,则依据__all__后面列举的名字使用。

 

posted @   *sunflower*  阅读(66)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示