Python迭代器的实现原理
作者:??编程学习网???? 时间:2022-12-13 09:26:22
前言:
在Python里面,只要类型对象实现了__iter__,那么它的实例对象就被称为可迭代对象(Iterable),比如字符串、元组、列表、字典、集合等等。而整数、浮点数,由于其类型对象没有实现__iter__,所以它们不是可迭代对象。
from typing import Iterable
print(
isinstance("", Iterable),
isinstance((), Iterable),
isinstance([], Iterable),
isinstance({}, Iterable),
isinstance(set(), Iterable),
) # True True True True True
print(
isinstance(0, Iterable),
isinstance(0.0, Iterable),
) # False False
可迭代对象的一大特点就是它可以使用for循环进行遍历,但是能被for循环遍历的则不一定是可迭代对象。
我们举个栗子:
class A:
def __getitem__(self, item):
return f"参数item: {item}"
a = A()
#内部定义了 __getitem__
#首先可以让实例对象像字典一样访问属性
print(a["name"]) # 参数item: name
print(a["satori"]) # 参数item: satori
# 此外还可以像可迭代对象一样被for循环
# 循环的时候会自动给item传值,0 1 2 3...
# 如果内部出现了StopIteration,循环结束
# 否则会一直循环下去。这里我们手动break
for idx, val in enumerate(a):
print(val)
if idx == 5:
break
"""
参数item: 0
参数item: 1
参数item: 2
参数item: 3
参数item: 4
参数item: 5
"""
所以实现了__getitem__的类的实例,也是可以被for循环的,但它并不是可迭代对象。
from typing import Iterable
print(isinstance(a, Iterable)) # False
打印的结果是 False。
总之判断一个对象是否是可迭代对象,就看它的类型对象有没有实现__iter__。可迭代对象我们知道了,那什么是迭代器呢?很简单,调用可迭代对象的__iter__方法,得到的就是迭代器。
迭代器的创建
不同类型的对象,都有自己的迭代器,举个栗子:
lst = [1, 2, 3]
#底层调用的其实是list.__iter__(lst)
#或者说PyList_Type.tp_iter(lst)
it = lst.__iter__()
print(it) # <list_iterator object at 0x000001DC6E898640>
print(
str.__iter__("")
) # <str_iterator object at 0x000001DC911B8070>
print(
tuple.__iter__(())
) # <tuple_iterator object at 0x000001DC911B8070>
迭代器也是可迭代对象,只不过迭代器内部的__iter__返回的还是它本身。当然啦,在创建迭代器的时候,我们更常用内置函数iter。
lst = [1, 2, 3]
# 等价于 type(lst).__iter__(lst)
it = iter(lst)
但是iter函数还有一个鲜为人知的用法,我们来看一下:
val = 0
def foo():
global val
val += 1
return val
# iter可以接收一个参数: iter(可迭代对象)
# iter也可以接收两个参数: iter(可调用对象, value)
for i in iter(foo, 5):
print(i)
"""
1
2
3
4
"""
进行迭代的时候,会不停地调用接收的可调用对象,直到返回值等于传递第二个参数value,在底层被称为哨兵,然后终止迭代。
我们看一下iter函数的底层实现:
static PyObject *
builtin_iter(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *v;
// iter函数要么接收一个参数, 要么接收两个参数
if (!_PyArg_CheckPositional("iter", nargs, 1, 2))
return NULL;
v = args[0];
//如果接收一个参数
//那么直接使用 PyObject_GetIter 获取对应的迭代器即可
//可迭代对象的类型不同,那么得到的迭代器也不同
if (nargs == 1)
return PyObject_GetIter(v);
// 如果接收的不是一个参数, 那么一定是两个参数
// 如果是两个参数, 那么第一个参数一定是可调用对象
if (!PyCallable_Check(v)) {
PyErr_SetString(PyExc_TypeError,
"iter(v, w): v must be callable");
return NULL;
}
// 获取value(哨兵)
PyObject *sentinel = args[1];
//调用PyCallIter_New
//得到一个可调用的迭代器, calliterobject 对象
/*
位于 Objects/iterobject.c 中
typedef struct {
PyObject_HEAD
PyObject *it_callable;
PyObject *it_sentinel;
} calliterobject;
*/
return PyCallIter_New(v, sentinel);
}
来源:https://juejin.cn/post/7091845218299248647
标签:Python,迭代器,原理
0
投稿
猜你喜欢
ES6 let和const定义变量与常量的应用实例分析
2024-05-28 15:41:17
Python使用回溯法子集树模板获取最长公共子序列(LCS)的方法
2021-04-14 04:55:49
javascript实现鼠标选取拖动或Ctrl选取拖动
2021-08-21 19:08:33
用Python实现QQ游戏大家来找茬辅助工具
2021-09-10 16:28:44
Firefox下无法正常显示年份的解决方法
2024-04-18 09:39:50
Array.prototype.slice
2010-05-07 12:43:00
关于python的bottle框架跨域请求报错问题的处理方法
2021-12-06 23:00:11
Python Json模块中dumps、loads、dump、load函数介绍
2021-03-20 11:21:20
一篇文章搞定数据库连接池
2024-01-19 02:55:49
pandas.DataFrame.to_json按行转json的方法
2022-11-09 11:24:23
详解vue+webpack+express中间件接口使用
2024-04-29 13:11:10
学点简单的Django之第一个Django程序的实现
2021-03-23 05:10:59
可能是最全面的 Python 字符串拼接总结【收藏】
2023-10-06 14:29:20
python递归实现快速排序
2023-08-26 22:46:27
Vue按回车键进行搜索的实现方式
2024-05-05 09:06:27
使用python生成云词图实现画红楼梦词云图
2022-07-19 00:21:56
python发送伪造的arp请求
2022-11-24 00:47:35
高手进阶:网页设计中的文字运用
2008-10-05 08:58:00
C#连接db2数据库的实现方法
2024-01-19 07:00:51
python 识别登录验证码图片功能的实现代码(完整代码)
2021-03-14 23:03:40