Python基础篇---生成器和模块

本章内容

       • 生成器对象

       • 自定义range方法

       •  yield关键字作用

       •  生成器表达式

       •  模块

生成器对象


 生成器对象其本质是自定义迭代器,就是需要我们自己写代码产生的迭代器。

生成器对象也是节省存储空间的 特性与迭代器对象一致。

def index():
    print('第一次输出')
    yield 1
    print('第二次输出')
    yield 2
1
2
3
4
5
6
7
8
9
10
当我们没有加括号调用之前,它就是一个普通的函数
        print(index)  # <function index at 0x1096c0ea0>
加括号调用并接收结果,不执行代码,而是变成生成器对象(迭代器)
        res = index()  # print(res)  # <generator object index at 0x11da33468>
        res有了iter()和next()方法
变成生成器对象之后调用__next__就会开始执行函数体代码
        调用一次next:
        print(res.__next__())  #第一次输出 1   yield有点像return的功能 停止在这里
        print(res.__next__())  #第二次输出 2  
        print(res.__next__())  # 报错

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

再次执行__next__基于上次的位置继续往后执行到下一个yield关键字处,

如果没有了 再执行也会报错。

 

 

自定义range方法


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

需求:通过生成器模拟range方法。

def my_range():
    pass
for i in my_range(1,10):
    print(i)

先实现range2个参数的最简单情况。

def range(start, end):  # start为开始 end为结束
    while start < end:  # 设置一个循环 去迭代start+1
        yield start  # 每一次循环都返回start
        start += 1  # 迭代
for i in range(1, 10):
    print(i)

特殊情况,只有一个参数的情况。

复制代码
def range(start, end=None):  # start为末尾值 end可以不传值 应该设置成默认参数
    if not end:  # 没有给end传值 end=None 代码层面做判断 将形参数据做替换处理
        end = start  
        start = 0
    while start < end:  # 设置一个循环 去迭代x+1
        yield start  # 每一次循环都返回x
        start += 1  # 迭代
for i in range(1, 10):
    print(i)
复制代码

三个参数情况,传入了步长。

复制代码
def range(start, end=None,step=1):  # 给函数添加第三个形参 并且设置成默认参数 默认值是1  step=1
    if not end:  # 没有给end传值 end=None 代码层面做判断 将形参数据做替换处理
        end = start
        start = 0
    while start < end:  # 设置一个循环 去迭代x+1
        yield start  # 每一次循环都返回x
        start += step  # 每次递增的时候只需要递增step的数值即可
for i in range(1, 10):
    print(i)
复制代码

写代码一定不要想太多,先搭建主题功能,之后再考虑其他情况,思路一定要清晰!!!

yield关键字作用


1
2
3
4
5
yield的作用:
    在函数体代码中出现 可以将函数变成生成器
    在执行过程中 可以将后面的值返回出去 类似于return
    还可以暂停住代码的运行
    还可以接收外界的传值(了解)
复制代码
def go_home(name):
    print(f'{name}在回家路上')
    while True:
        home= yield
        print(f'{name}到家了{home}')
res = go_home('jason')
# 想执行一次代码  如果想执行多次直至结束 可以直接用for循环
res.__next__()
res.__next__()
# 给yield传值
res.send('没有钥匙')  # 可以给yield传值 并且自动调用一次__next__方法
res.send('有钥匙')  # 可以给yield传值 并且自动调用一次__next__方法
复制代码

生成器表达式


 生成器表达式也是为了节省存储空间,用来做代码优化,前期学习可以忽略。

# 生成器表达式
res = (i for i in 'jason')  
print(res)  # <generator object <genexpr> at 0x0000022C8D360D00>
print(res.__next__())  # j
print(res.__next__())  # a
print(res.__next__())  # s
"""生成器内部的代码只有在调用__next__迭代取值的时候才会执行"""

下面有一个生成器表达式的例题,诀窍在于生成器的调用。

复制代码
# 普通的求和函数
def add(n, i):
    return n + i
# 生成器对象 返回 0 1 2 3
def test():
    for i in range(4):
        yield i
# 将test函数变成生成器对象
g = test()
# 简单的for循环
for n in [1, 10]:
    g = (add(n, i) for i in g)
    """
    第一次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)

#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]
"""正确答案是C  诀窍就是抓n是多少即可"""
复制代码

模块


 简介

模块就是一系列功能的结合体,可以直接使用,极大地提升开发效率。

模块的三种来源

1
2
3
4
5
6
内置的模块
    无需下载 解释器自带  直接导入使用即可
自定义模块
    自己写的代码 封装成模块 自己用或者发布到网上供别人使用
第三方模块
    别人写的发布到网上的 可以下载使用的模块(很多牛逼的模块都是第三方)

模块的四种表现形式

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

模块的两种导入方式


要想使用模块,必须先把模块导入,而导入的方法有两种。

方式1---import...句式

import md  # 导入md模块
print(md.name)  #调用md模块中的名称
md.read1()   # 调用md模块里的函数

import句式的特点

1
2
可以通过import后面的模块名点的方式 使用模块中所有的名字
并且不会与当前名称空间中的名字冲突(指名道姓)  

 模块导入的原理

1
2
3
4
5
6
7
8
执行当前文件 产生一个当前文件的名称空间
执行import句式 导入模块文件(即执行模块文件代码产生模块文件的名称空间)
在当前文件的名称空间中产生一个模块的名字 指向模块的名称空间
通过该名字就可以使用到模块名称空间中的所有数据
ps:相同的模块反复被导入只会执行一次
         import md   有效
         import md   无效(写了跟没写一样)
         import md   无效(写了跟没写一样)

 

方式2---from...import...句式

from md import name  # 导入模块中的名称name  其他的没有导入进来
print(name)  # jasonNB
name = 'kevin'
print(name)  # kevin

from...import...句式特点

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

from...import...的原理

1
2
3
执行当前文件产生一个名称空间
执行导入语句 运行模块文件产生名称空间存放运行过程中的所有名字
将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
# 连续导入多个模块,这多个模块最好有相似的功能部分,如果没有建议分开导入,如果是同一个模块下的多个变量名无所谓!!!

3.通用导入

from md import *
#   *表示md里面所有的名字   from...import的句式也可以导入所有的名字
#   如果模块文件中使用了__all__限制可以使用的名字  
#   那么*号就会失效 依据__all__后面列举的名字

 

posted @   早安_1207  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
返回顶端
点击右上角即可分享
微信分享提示