python语言基础-5 进阶语法-5.1 推导式、生成器与迭代器

news2024/11/16 8:40:32

声明:本内容非盈利性质,也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站,会尽量附上原文链接,并鼓励大家看原文。侵删。

5 进阶语法

5.1 推导式、生成器与迭代器

python为了简化语法方便计算,提供了很多便捷的基础语法。推导式、生成器与迭代器就是这样一种语法。

5.1.1 推导式

推导式的作用是通过原有可迭代类型变量按指定运算规则生成一个新的可迭代类型变量。

推导式有如下四种:

  • 条件推导式:根据条件选择表达式进行输出;(条件推导式是其他三种推导式的基础)
  • 列表推导式:由旧列表根据指定运算规则形成新列表;
  • 集合推导式:由旧集合根据指定运算规则形成新集合;
  • 字典推导式:由旧字典根据指定运算规则形成新字典。

四种推导式的形式如下示例:

'''
条件推导式格式:表达式1 if 判断条件 else 表达式2。如果满足条件则执行表达式1,否则执行表达式2
'''
# 新手代码
x = 10
if x%2 == 0:
    print("新手说:x是偶数")
else:
    print("新手说:x是奇数")
# 老司机
x = 15
print("老司机说:x是偶数") if x%2 == 0 else print("老司机说:x是奇数")
'''
输出结果:
新手说:x是偶数
老司机说:x是奇数
'''


'''
列表推导式格式:[表达式 for 变量 in 旧列表] or [表达式 for 变量 in 旧列表 if 条件]
'''
# 过滤长度小于等于3的人名
names = ['tom', 'lily', 'abc', 'jack', 'steven', 'bob', 'ha']
result = [name for name in names if len(name) > 3]
print(result)
'''
上面这个例子,如果不使用表达式,则要定义函数用for循环实现
def func(names):
    newlist = []
    for name in names:
        if len(names)>3:
            newlist.append(name)
    return newlist

'''

# 表达式中可以不加条件
newlist3 = [i[-1] for i in newlist2]  # 取出newlist2中元组元素的第二个值

# 0~5范围的奇偶元素列表:表达式中可以用双层循环(双层循环产生的元素是笛卡尔积的形式),表达式可以生成元组型元素
newlist2 = [(x, y) for x in range(5) if x % 2 == 0 for y in range(10) if y % 2 != 0]
print(newlist2)

# 由字符串生成的列表推导式:取出字符串中所有的a
s1 = "aabbaaeaacae"
s2 = [s for s in s1 if s=='a']
print(s2)


'''
集合推导式格式:{表达式 for 变量 in 旧系列} or {表达式 for 变量 in 旧系列 if 条件}
'''

# 列表去重并加1
list1 = [1, 2, 1, 3, 5, 2, 1]
set1 = {x+1 for x in list1}
print(set1)


'''
字典推导式格式:与列表和集合的推导式相似
'''
dict1 = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}
newdict = {value:key for key, value in dict1.items()}   # 其中value:key表示要交换key与valeu的位置,for key, value in dict1.items()表示对旧字典进行遍历;
print(newdict)

5.1.2 生成器

通过列表推导式,我们可以直接创建一个列表,然而生成的列表是要占用内存空间的。如果我们创建大量元素的列表,却仅仅需要访问几个元素或多次访问每次访问几个元素,会浪费内存空间。因此,我们在每次调用时产生一个值,这样产生变量占用的内存空间就小多了。在python中这种逐个计算产生数值的机制称为生成器(generator)。

生成器有两种形式:推导式形式的生成器与函数形式的生成器

(1)推导式形式的生成器

推导式形式的生成器与推导式十分相似,如下:

'''
得到这样一串数值[0,3,6,9,12,...,27]
'''
# 如果使用列表推导式方法
newlist = [x*3 for x in range(20)]
print(newlist)

# 创建生成器
g = (x*3 for x in range(20))  # 推导式中的表达式不变,把方括号变为小括号即可
print(type(g))  # 生成器的类型

# 使用生成器产生数值:
print(g.__next__())  # 使用.__next__()方法产生数值;
print(next(g))  # 使用next()函数产生数值;

执行以上例子可以看出:使用生成器时,调用一次产生一个数值,再调用一次产生下一个数值,这就是逐个计算。

值得注意的是,生成器内部是一个列表推导式,它的长度是有限的,如果取值的次数超过了长度限制,将会报错。如下:

# 调用次数超过了表达式的范围,则会出现异常,解决此异常:
g = (x*3 for x in range(20))
while True:
    try:
        e = next(g)
        print(e)
    except:
        print('元素产生完毕!')
        break

(2)函数形式的生成器

在函数中使用yield抛出数值就可以创建一个生成器(函数中只要存在这条语句就是一个生成器)。如下:

# 创建一个生成器函数
def func():
    n = 0
    while True:
        n += 1
        yield n  # yield的出现使语句执行到这里就执行抛出数值并暂停执行,不接到调用生成器的命令就不会往下执行
g = func()  # 用一个变量接收,该变量即成为一个生成器

# 使用生成器产生数值
print(next(g))

与推导式形式的生成器相比,函数式的生成器更方便使用复杂计算规则。比如下面的例子:

# 菲波那契数列的生成:
def fib(length):
    a, b = 0, 1
    n = 0
    while n < length:
        yield b
        a, b = b, a + b
        n += 1
    return '没有更多元素了!'  # 函数生成器的终止提示信息一般由return完成

g = fib(8)
print(next(g))

# 如果使用函数形式的生成器,可以在知道菲波那契数列递推式的情况下很方便地计算每个元素。然而,如果使用的是推导式形式的生成器,就要使用通项式,或想办法在通项n与元素之间建立关联,这种算法考虑起来是比较复杂的。

函数式的生成器也是逐个计算,由其中的yield关键字的作用,可以很清楚地了解到生成器的执行过程:本质上还是使用循环执行一次产生一个数值;调用一次生成器则循环执行一次,当本次执行遇到yield语句时,阻塞执行并抛出数值;当下一次调用生成器时,接着执行一次循环,并由yield语句阻塞执行并抛出数值。因此,推导式生成器与函数生成器最大的区别其实在于,推导式生成器中常使用for循环,且yield语句是隐式执行的;而函数生成器中两种循环都使用,且yield语句是显式存在的。

推导式生成器调用次数超过了限制会产生异常,函数生成器也一样。由生成器的执行过程可知,生成器抛出异常的根本原因其实是执行循环超过了次数限制。

函数式的生成器是可以通过生成器对函数进行传参的。如下:

# 创建一个生成器函数
def gen():
    i = 0
    while i < 5:
        temp = yield i # 这里使用yield对temp变量进行了赋值
        print('temp:', temp)
        for x in range(temp):  # 这里的temp对for循环长度做了限定
            print('-->', x)
        i += 1
    return '没有更多值了!'

# 创建一个生成器
g = gen()

# 用常规方式调用生成器
print(next(g))  # 根据打印的结果为“0”可知,第一次执行在yield处暂停且抛出的值是0;
print(next(g))  # 当第二次执行时,接着yield后执行,打印出“temp: None”并且报错了。因为yield语句没有对temp进行赋值,temp值为None;而None是不能作为整数的,temp对range(temp)来说是无效参数,因此报错了;
print(next(g))  # 第三次调用,及后面几次调用,都会是一样的结果
g.__next__()
g.__next__()
g.__next__()

# 如果要正常使用这个生成器,可以在用send方法可以对temp传值的情况下调用
print(g.send(None))  # 第一次调用,.send()方法传值必须为None。因为.send()方法是没有指定形参为temp的,之所以知道要传参给temp,是要靠None确定yield语句所在的赋值语句的变量是temp;
print(g.send(2))  # 以后调用就可以传递整数类型的参数。只要保证长度大于等于调用次数,就不会报错
n1 = g.send(5)
print('n1', n1)

(3)生成器的应用

在写协程的时候会使用到生成器,以实现任务的交替执行。(协程与线程的关系相当于线程与进程的关系,后面会介绍)

如下:

# 生成器帮助函数交替执行
def task1(n):
    for i in range(n):
        print('正在搬第{}块砖!'.format(i))
        yield None


def task2(n):
    for i in range(n):
        print('正在听第{}首歌!'.format(i))
        yield None


# 如果不函数定义为生成器则由于代码的顺序执行,无法完成两个函数语句的交替输出

# 采用生成器的方式进行输出,写协程就会采用这种方式,使任务交替执行
g1 = task1(10)
g2 = task2(5)

while True:
    try:
        g1.__next__()
        g2.__next__()
    except:
        break

5.1.3 迭代器

(1)可迭代对象

认识迭代器之前,我们先要了解一个概念是可迭代对象。可迭代对象是指可迭代类型(Iterable)及其子类型的对象。python中的可迭代类型具体有以下几种:

  • 对象类型:生成器;
  • 基本类型:元组、列表、集合、字典、字符串。

判断变量是否为可迭代类型,可以使用isinstance()函数:

# isinstance()函数用于判断某个子类型对象是否是某个父类型,即判断两个类型之间是否有继承关系。因此,我们可以判断所创建的变量与可迭代类型Iterable之间是否有继承关系,从而确定变量是否是可迭代类型
from collections.abc import Iterable  # 3.8之前版本是form collections import Iterable

list1 = [1, 4, 7, 8, 8]
f = isinstance(list1, Iterable)  #判断列表是否可迭代,isinstance()函数用于作判断,括号里第一个参数是要判断的对象,后一个参数是要判断的类型
print(f)

f = isinstance('abc', Iterable)
print(f)

f = isinstance(100, Iterable)
print(f)  # 由打印结果可知,整型不是可迭代类型;

g = (x+1 for x in range(10))
f = isinstance(g,Iterable)  # 判断生成器是否是可迭代的
print(f)

(2)迭代器

迭代是一种逐个使用集合中元素的访问方式,逐个使用就需要遍历,遍历就需要记住当前访问元素的位置,而迭代器就是记住取出元素位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有元素访问完结束,这期间迭代器只能前进不能后退。

从特征上来看,可以被next()函数调用并不断返回下一个值的对象(或变量)称为迭代器:Iterator。

由迭代器的定义与性质可知:可迭代对象不一定都是迭代器。比如:生成器是一种迭代器,但列表、元组等并不是。

我们可以将可迭代对象变为迭代器,使用的方法函数是iter()。如下:

list1 = [1,2,3,4,5,6]
list1 = iter(list1)  #将列表变为iterator
print(next(list1))
print(next(list1))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2241392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IoT [remote electricity meter]

IoT [remote electricity meter] 物联网&#xff0c;远程抄表&#xff0c;电表数据&#xff0c;举个例子

sql数据库-排序查询-DQL

目录 语法 排序方式 举例 将表按年龄从小到大排序 将表按年龄从大到小排序 ​编辑 多重排序 将表按年龄升序&#xff0c;年龄相同按入职时间降序 语法 select * from 表名 order by 字段名1 排序方式1&#xff0c;字段2 排序方式2; 排序方式 升序&#xff1a;ASC&…

在spring boot工程中使用Filter时,@WebFilter 注解不生效的问题分析和解决方案

1. 问题描述 首先编写一个Filter类并通过Component放入spring容器中&#xff0c;通过实现jakarta.servlet中提供的Filter接口完成过滤器的创建&#xff0c;代码如下。 import jakarta.servlet.*; import jakarta.servlet.annotation.WebFilter; import org.springframework.st…

学习threejs,使用TWEEN插件实现动画

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.PLYLoader PLY模型加…

TypeScript在现代前端开发中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 TypeScript在现代前端开发中的应用 TypeScript在现代前端开发中的应用 TypeScript在现代前端开发中的应用 引言 TypeScript 概述…

CTF-Crypto-简单加密

打开首页看题目 描述看起来是一段乱码&#xff0c;拉入随波逐流&#xff0c;未解决 e6Z9i~]8R~U~QHE{RnY{QXg~QnQ{^XVlRXlp^XI5Q6Q6SKY8jUAA 观察字符串&#xff0c;末尾是AA&#xff0c;其中可能含有base64加密 找寻Ascll码表&#xff0c;发现A的Ascll是65&#xff0c;的Ascl…

MacOS下,如何在Safari浏览器中打开或关闭页面中的图片文字翻译功能

MacOS下&#xff0c;如何在Safari浏览器中打开或关闭页面中的图片文字翻译功能 在Mac上的Safari浏览器中&#xff0c;可以通过实况文本功能来实现图片中的文本翻译。关闭步骤具体步骤如下&#xff1a; 在浏览器地址栏&#xff0c;鼠标右击翻译按钮&#xff0c;然后点击“首选…

操作系统——虚拟存储器(含思维导图)

本教材为中国铁道出版社——操作系统&#xff08;第四版&#xff09;刘振鹏、张明、王煜著。本篇文章为第六章复习。 目录 思维导图&#xff1a; ​编辑一、虚拟存储器 1.理论基础 2.定义 二、分页虚拟存储管理 1.基本原理 2.缺页中断 3.页面置换 &#xff08;1&…

基于8.0 Update 3b 的ESXi-Arm Fling

很久没有更新过 ESXi-Arm 的版本了&#xff0c;博通旗下的 VMware 居然把它更新到了 8.0U3b。 下载地址&#xff1a;https://community.broadcom.com/flings 我准备使用离线更新&#xff0c;就没有下载 ISO&#xff0c;直接下载ESXi-Arm-Offline-Depot-2_00-dl.zip scp 上传…

python解析网页上的json数据落地到EXCEL

安装必要的库 import requests import pandas as pd import os import sys import io import urllib3 import json测试数据 网页上的数据结构如下 {"success": true,"code": "CIFM_0000","encode": null,"message": &quo…

C#桌面应用制作计算器

C#桌面应用制作简易计算器&#xff0c;可实现数字之间的加减乘除、AC按键清屏、Del按键清除末尾数字、/-按键取数字相反数、%按键使数字缩小100倍、按键显示运算结果等...... 页面实现效果 功能实现 布局 计算器主体使用Panel容器&#xff0c;然后将button控件排列放置Pane…

谷歌推出设备内置人工智能,实时向手机用户发出诈骗电话警报

Google 宣布推出适用于 Android 的新安全功能&#xff0c;可实时防御诈骗和有害应用。 这些功能由先进的设备内置 AI 提供支持&#xff0c;可在不损害隐私的情况下增强用户安全性。 这些新的安全功能首先在 Pixel 上推出&#xff0c;并将很快在更多 Android 设备上推出。 诈…

HarmonyOS ArkTs 解决流式传输编码问题

工作日志 日期&#xff1a;2024-11-15 标题&#xff1a;HarmonyOS ArkTs 解决流式传输编码问题 问题描述 问题&#xff1a;在处理流式数据的 HTTP 请求时&#xff0c;服务器返回的数据存在编码问题&#xff0c;导致数据无法正确地解码为字符串。部分数据在解码后出现了乱码…

MySQL数据库最大连接数查询及修改

MySQL数据库最大连接数查询及修改 1. 客户端连接数超出异常案例 Navicat连接异常信息如下&#xff1a; 2. 查看MySQL最大客户端连接数 通过mysql client命令登录MySQL数据库&#xff08;登录用户不受限制&#xff0c;既可以是 root管理员用户&#xff0c;也可以是常规用户&a…

使用Wireshark获取USB HID(Human Interface Device)报告描述符

使用Wireshark选择需要获取的USB进行抓取数据&#xff0c;找到设备&#xff08;host&#xff09;接收信息的数据 第二栏出现hid报告&#xff0c;右击选择复制流 将复制的内容粘贴到USB标准请求及描述符在线分析工具 - USB中文网 进行解析 以图中获取手写板的数据为例&#xff…

TofuAI处理BT1120时序视频要求

时序要求 BT.1120视频用于1920x108030Hz数字视频输入。具体时序必须严格按照说明。BT.1120输入电平为1.8V。 BT1120数字视频采用YCbCr彩色格式输出&#xff0c;串行数据位宽为16bit&#xff0c;亮度在 高8bit&#xff0c;色度在低8bit&#xff0c;亮度和色度在同一个时钟周期输…

聊天服务器(8)用户登录业务

目录 登录状态业务层代码数据模型层代码记录用户的连接信息以及线程安全问题客户端异常退出业务 登录状态 登录且状态变为online 业务层代码 #include "chatservice.hpp" #include "public.hpp" #include <string> #include <muduo/base/Loggi…

通用定时器---输出比较功能

目录 一、概念 二、输出比较的8种模式 三、输出比较输出PWM波形的基本结构 配置步骤 四、示例代码 一、概念 OC&#xff08;OutPut Compare&#xff09;输出比较。输出比较可以通过比较CNT与CCR寄存器的关系&#xff0c;来对输出电平进行置1/置0/翻转的操作&#xff0c;可…

Wireshark中的length栏位

注&#xff1a;Ethernet II的最小data length为46&#xff0c;如果小于&#xff0c;会补全到46. 1.指定网卡抓取的&#xff0c;链路为ethernet。 IPv4 Ethernet II 长度为 14 bytes - L1ipv4 header中的length包括header和payload的总长度 - L2wireshark中length表示抓取的pac…

spring boot整合https协议

整体目录 1. 生成SSL证书 首先&#xff0c;使用keytool生成一个自签名证书。打开命令行工具并运行以下命令&#xff1a; keytool -genkeypair -alias myserver -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 365 这将创建一个名为keystore.jks的文件&#xf…