Python中可迭代与不可迭代的区分与应用(一文读懂)

在Python中,迭代是数据处理的核心机制。无论是遍历列表、读取文件,
还是使用map/filter等函数式编程工具,都离不开可迭代对象。
避免混淆可迭代对象、迭代器、序列等概念,是写出更优雅高效的代码前提。

一、基本概念

1. 什么是迭代

  • 官网文档:
An object capable of returning its members one at a time.
可迭代对象是一种能够一次返回其一个成员的对象。Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements sequence semantics.
可迭代对象的例子包括所有的序列类型(例如 list、str 和 tuple)和一些非序列类型,比如 dict、文件对象,以及任何定义了 iter() 方法或定义了实现序列语义的 getitem() 方法的类所创建的对象。
  • “迭代”词义:汉语词汇,拼音为dié dài,原指事物更相代替、轮换的过程,在计算机科学领域中,迭代通常涉及将每次迭代的结果作为下一次迭代的初始值,从而实现对问题的逐步求解。
  • 所以“迭代”是解决问题的方法论。

2. 可迭代对象 vs 不可迭代对象

1). 我们判断一个对象是否可迭代,最重要的特征就是,任何能够一次返回其一个成员的对象都称为可迭代对象。它不一定是一个“存储好的”完整序列(如列表),而可以是按需生成下一个值的对象,例如range()函数。

列表:[1, 2, 3] → 你可以逐个取出
字符串:“hello” → 你可以逐个字符读取
字典:{“a”: 1} → 你可以逐个取出键
文件对象:可以逐行读取

例如:会依次返回1、2、3:

for item in[1,2,3]:print(item)

2). 尝试迭代不可迭代对象就会报错,下面案例中可以看到,我们对数值型变量进行遍历时,程序会报错:TypeError: ‘int’ object is not iterable:

item =123for i in item:print(i)

3). 区分可迭代对象、不可迭代对象

  1. 能使用 for 循环遍历的 → 可迭代对象
  2. 能使用 iter() 函数获取迭代器的 → 可迭代对象
  3. 能用 isinstance(obj, Iterable) 返回 True → 可迭代对象
from collections.abc import Iterable # 判断常见类型是否为可迭代对象print(isinstance([1,2,3], Iterable))# Trueprint(isinstance("hello", Iterable))# Trueprint(isinstance((1,2,3), Iterable))# Trueprint(isinstance({1,2,3}, Iterable))# Trueprint(isinstance({'a':1}, Iterable))# Trueprint(isinstance(123, Iterable))# False
  1. 数字、布尔值、None、函数 → 通常不可迭代

例如:

对象类型是否可迭代示例可迭代原因
列表[1, 2, 3]实现了 __iter__() 方法
元组(1, 2, 3)实现了 __iter__() 方法
字符串"hello"实现了 __iter__() 方法
字典{"a": 1}实现了 __iter__() 方法
集合{1, 2, 3}实现了 __iter__() 方法
整数42没有迭代协议
浮点数3.14没有迭代协议
布尔值True没有迭代协议
NoneNone没有迭代协议
函数def f(): pass没有迭代协议

4). 深入辨析:混淆对象和可迭代容器

# 错误示例 data ={"name":"Alice","age":25}try:for item in data["name"]:# 这里迭代的是字符串"Alice"print(item)# 这会工作,但可能不是你想要的except Exception as e:print(f"错误: {e}")# 你可能想这样做:for key in data:# 迭代字典的键print(f"{key}: {data[key]}")

5). 不可迭代对象

就像 ​一块石头,你无法从中“取出”多个部分。

a. 内置不可迭代对象
from collections.abc import Iterable # 1. 整数 (int) num =42print(isinstance(num, Iterable))# False# 尝试迭代会报错: TypeError: 'int' object is not iterable# 2. 浮点数 (float) pi =3.14159print(isinstance(pi, Iterable))# False# 尝试迭代会报错: TypeError: 'float' object is not iterable# 3. 布尔值 (bool) flag =Trueprint(isinstance(flag, Iterable))# False# 尝试迭代会报错: TypeError: 'bool' object is not iterable# 4. Noneprint(isinstance(None, Iterable))# False# 尝试迭代会报错: TypeError: 'NoneType' object is not iterable# 5. 函数对象defmy_func():return"hello"print(isinstance(my_func, Iterable))# False# 尝试迭代会报错: TypeError: 'function' object is not iterable# 6. 类对象classMyClass:pass obj = MyClass()print(isinstance(obj, Iterable))# False# 尝试迭代会报错: TypeError: 'MyClass' object is not iterable
b. 尝试迭代不可迭代对象
# 错误示例 number =123try:for digit in number:# TypeError: 'int' object is not iterableprint(digit)except TypeError as e:print(f"错误: {e}")# 解决方案1:转换为可迭代对象 number =123for digit instr(number):# 将数字转换为字符串print(digit)# 输出: 1, 2, 3# 解决方案2:使用适当的容器 number =123 digits =[int(d)for d instr(number)]# 转换为列表for digit in digits:print(digit)# 输出: 1, 2, 3

3. 可迭代对象的内部机制

  • 官网文档:
Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), …).
可迭代对象可以在for循环中使用,也可以在需要序列的许多其他地方使用(例如zip()、map()等)。When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object.
当可迭代对象作为参数传递给内置函数iter()时,它会返回该对象的迭代器。This iterator is good for one pass over the set of values.
这个迭代器适用于对值集合进行一次遍历。When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself.
使用可迭代对象时,通常不需要自己调用iter()或处理迭代器对象。The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop.
for语句会自动为你完成这些操作,它会创建一个临时的无名变量来在循环期间保存迭代器。
常见错误

误用一次性迭代器

# 错误 data =[1,2,3] squared =map(lambda x: x**2, data)print(list(squared))# [1, 4, 9]print(list(squared))# [] ← 空了!# 正确:重新创建或先转换为列表 squared =map(lambda x: x**2, data) result =list(squared)# 立即转换为列表保存print(result)# [1, 4, 9]print(result)# [1, 4, 9] ← 可重复使用

二、迭代性的应用

说明:均为伪代码

1. 数据库查询结果分页处理

# 假设有1000万条记录# ❌ 错误:一次性取出 results = db.query("SELECT * FROM huge_table")# 内存爆炸# ✅ 正确:使用迭代器defbatch_fetch(query, batch_size=1000):"""批量获取,迭代器实现""" offset =0whileTrue: batch = db.query(f"{query} LIMIT {batch_size} OFFSET {offset}")ifnot batch:breakfor record in batch:yield record offset += batch_size # 使用for record in batch_fetch("SELECT * FROM huge_table"): process(record)# 每次只加载1000条到内存

2. 实时数据流处理

# 监控系统日志,实时报警deftail_log(file_path):"""模拟 tail -f,无限迭代器"""withopen(file_path)as f: f.seek(0,2)# 移动到文件末尾whileTrue: line = f.readline()ifnot line: time.sleep(0.1)# 等待新内容continueyield line.strip()# 实时处理日志for log_line in tail_log("/var/log/system.log"):if"ERROR"in log_line: send_alert(log_line)# 实时报警

3. 分块处理大数据

defprocess_in_chunks(iterable, chunk_size=1000):"""将大数据分块处理""" iterator =iter(iterable)while chunk :=list(itertools.islice(iterator, chunk_size)): process_chunk(chunk)

4. 数据管道

defdata_pipeline(source):"""数据清洗管道"""# 每一步都是惰性的 cleaned =(item.strip()for item in source)# 去空格 filtered =(item for item in cleaned if item)# 过滤空值 transformed =(item.upper()for item in filtered)# 转大写return transformed 

5. 从"集合思维"到"流思维"

# 集合思维:先准备好所有数据defprocess_files_collection(files): all_data =[]forfilein files:withopen(file)as f: all_data.append(f.read())# 现在才开始处理...for data in all_data: process(data)# 流思维:边获取边处理defprocess_files_stream(files):forfilein files:withopen(file)as f:for line in f:# 迭代器,逐行处理 process(line)# 立即处理,不等待

6. 从"命令式"到"声明式"

# 命令式:详细描述如何做defget_top_students(students, n=3): result =[]for student in students:if student.score >90: result.append(student) result.sort(key=lambda s: s.score, reverse=True)return result[:n]# 声明式:描述要什么(使用迭代器工具)defget_top_students_declarative(students, n=3):returnsorted((s for s in students if s.score >90),# 生成器表达式 key=lambda s: s.score, reverse=True)[:n]

三、其他相关概念

说明:均为伪代码。

1、序列(sequence)

如列表、元组、字符串、字节,序列对象可测量其数据长度、支持索引(有序、可按编号访问指定位置的数据元素)。
由此看,序列一定是可迭代的,可迭代对象不一定是序列,如文件对象。

2、迭代器(iterator)

  • 官网文档:
An object representing a stream of data.
迭代器是表示数据流的对象。
Repeated calls to the iterator’s next() method (or passing it to the built-in function next()) return successive items in the stream.
重复调用迭代器的 next() 方法(或将其传递给内置函数 next())会返回流中的连续项。
When no more data are available a StopIteration exception is raised instead.
当没有更多数据可用时,会引发 StopIteration 异常。
At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again.
此时,迭代器对象已经耗尽,任何对其 next() 方法的进一步调用都只会再次引发 StopIteration。
Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted.
迭代器必须具有 iter() 方法,该方法返回迭代器对象本身,因此每个迭代器也是可迭代的,并且可以用在大多数接受可迭代对象的地方。
One notable exception is code which attempts multiple iteration passes.
一个值得注意的例外是尝试多次迭代的代码。
A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop.
容器对象(例如列表)每次传递给 iter() 函数或在 for 循环中使用时,都会生成一个全新的迭代器。
Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.
对迭代器尝试这样做只会返回与之前迭代过程中相同的已耗尽的迭代器对象,使其看起来像一个空容器。

总结:
迭代器是隐藏的取数员,是python在对数据进行迭代处理时的必要环节。

  • 迭代器是数据流​:它逐个产生值,可以表示有限或无限序列。
  • ​一次性消耗​:迭代器只能遍历一次,重新遍历需要重新获取迭代器。
  • ​迭代器也是可迭代的​:实现了__iter__(),因此可以用在for循环中,但注意其一次性。
  • ​生成器是迭代器​:生成器是创建迭代器的便捷方式,使用yield。
  • ​线程安全​:在多线程中使用迭代器需谨慎,可能需要额外同步。

  • 迭代器的一次性案例:
numbers =[1,2,3] iterator =iter(numbers)print(list(iterator))# [1, 2, 3]print(list(iterator))# [],迭代器已耗尽# 重新获取迭代器 iterator =iter(numbers)print(list(iterator))# [1, 2, 3]
  • 自定义迭代器类:
classSquares:"""生成从0到n-1的平方数"""def__init__(self, n): self.n = n self.current =0def__iter__(self):return self # 返回自身,因为自身就是迭代器def__next__(self):if self.current >= self.n:raise StopIteration result = self.current **2 self.current +=1return result squares = Squares(5)for sq in squares:print(sq)# 0, 1, 4, 9, 16
  • 生成器与迭代器的关系:
# 生成器是一种更简洁的迭代器实现方式defsquares_generator(n):for i inrange(n):yield i **2# 生成器函数返回一个生成器对象,它既是迭代器也是可迭代对象 gen = squares_generator(5)print(isinstance(gen, collections.abc.Iterator))# Trueprint(isinstance(gen, collections.abc.Iterable))# Truefor sq in gen:print(sq)

3、生成器(generator)

  • 官方文档:
A function which returns a generator iterator.
生成器函数是一种返回生成器迭代器的函数。
It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.
它看起来像一个普通函数,不同之处在于它包含 yield 表达式,用于生成一系列可在 for 循环中使用的值,或者可以一次一个地用 next() 函数获取。

4、递归

通过函数调用自身来解决问题。

例如:

# 经典例子:计算阶乘deffactorial(n):# 终止条件:最小套娃if n ==1:return1# 递归步骤:打开当前套娃,发现里面有个小一号的套娃else:return n * factorial(n -1)print(factorial(5))# 120

Read more

解锁Python数据采集与社交媒体分析新范式:Stweet无限制抓取技术探索指南

解锁Python数据采集与社交媒体分析新范式:Stweet无限制抓取技术探索指南 【免费下载链接】stweetAdvanced python library to scrap Twitter (tweets, users) from unofficial API 项目地址: https://gitcode.com/gh_mirrors/st/stweet 在数据驱动决策的时代,社交媒体平台蕴藏着海量有价值的信息。Stweet作为一款基于Python的高级数据采集工具,以其无API限制的特性和实时数据抓取能力,为研究者、数据分析师和开发者提供了前所未有的社交媒体数据获取途径。本文将带你深入探索Stweet的核心功能、创新特性及实战应用,助你掌握高效、合规的社交媒体数据采集技能。 核心功能解析:3种突破限制的采集技巧 Stweet的强大之处在于其能够绕过传统API的限制,直接从Twitter平台获取数据。其核心功能主要体现在以下三个方面: 1. 无限制搜索采集 传统的Twitter API往往对搜索结果数量、频率等方面设置严格限制,而Stweet通过模拟浏览器请求的方式,实现

By Ne0inhk

Trae CN IDE 中 Python 开发的具体流程和配置总结

以下是 Trae CN IDE 中 Python 开发的具体流程和配置总结,结合实例说明,帮助开发者快速上手: 一、环境准备 1. 安装 Trae CN IDE * 下载地址:访问 Trae 官网 下载对应操作系统的安装包(Windows .exe / macOS .dmg / Linux .tar.gz)。 * 安装步骤: * Windows:双击 .exe 文件,选择“创建桌面快捷方式”,按向导完成安装。 * macOS:将 .dmg 文件拖拽至 Applications 文件夹,首次启动需右键“打开”绕过安全限制。 * Linux:解压 .tar.gz 至

By Ne0inhk
Python Selenium全栈指南:从自动化入门到企业级实战

Python Selenium全栈指南:从自动化入门到企业级实战

🌟 嗨,我是Lethehong!🌟 🌍 立志在坚不欲说,成功在久不在速🌍 🚀 欢迎关注:👍点赞⬆️留言收藏🚀 🍀欢迎使用:小智初学计算机网页AI🍀 目录 一、自动化测试的革命性工具 1.1 浏览器自动化的价值 1.2 Selenium生态全景图 二、环境搭建与基础配置 2.1 全平台安装指南 2.1.1 基础组件安装 2.1.2 浏览器驱动自动化配置  2.2 跨浏览器配置矩阵 三、核心操作全解析 3.1 元素定位的八种武器 3.1.1 基础定位器 3.1.2 XPath高级技巧 3.2 页面交互完全手册

By Ne0inhk
【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控

【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控

📁【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控 🌈 个人主页:创客白泽 - ZEEKLOG博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。 👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦 概述 在数字化时代,数据备份已成为个人和企业数据管理的重要环节。本文将详细介绍如何使用Python开发一款功能全面的桌面级文件备份工具,该工具不仅支持即时备份,还能实现定时自动备份、增量备份等专业功能,并具备系统托盘驻留能力。通过tkinter+ttkbootstrap构建现代化UI界面,结合pystray实现后台运行,是Python GUI开发的经典案例。 功能亮点 1. 双目录选择:可视化选择源目录和目标目录 2. 三种备份模式: * 立即执行备份 * 每日/每周定时备份 * 精确到分钟的自定义时间备份 3. 增量备份机制:仅复制新增或修改过的文件 4. 实时日志系统:彩色分级日志输出 5. 进度可视化:

By Ne0inhk