网络编程
位置:首页>> 网络编程>> Python编程>> Python迭代器的实现原理

Python迭代器的实现原理

作者:??编程学习网????  发布时间:2022-12-13 09:26:22 

标签:Python,迭代器,原理

前言:

在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

0
投稿

猜你喜欢

  • 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达式就好办了匹配双字节字符(包括汉字在内
  • 前言其实就是个小问题,但是爆出来的时候也很莫名其妙。因为之前都跑得好好的,只是换了不同的文件去跑才出的问题,关键是不同的文件要处理的内容和格
  • 对于access数据库的日期时间类型字段存储的日期,直接从数据库中读出显示的效果是带时间的如,2009-06-13 18:00 ,如果只是希
  • 这个可以说属性选择符的JS版,用来遴选元素是适合不过。在开始之前,我们复习一下CSS2的属性选择符,JQuery高手可以跳过。属性选择符:名
  • 矛盾出来了,像我们这些小作坊,基本都是设计布局一人搞定。甚至还有加后台程序的。假设设计的时候考虑布局了,我们都有这个能力进行调整。但像大公司
  • 代码如下:'================================================== '函数名:
  • 有使用过VS2005开发工具的朋友或者其他语句如js中都有Try catch 语句块,那么在mysql中是否能有SQLserver的@@er
  • pytorch默认使用单精度float32训练模型,原因在于:使用float16训练模型,模型效果会有损失,而使用double(float6
  •  一、前言 JDK(Java Development Kit )是一切java应用程序的基础,可以说,所有的java应用程序是构建
  • 目的:JS+ASP打造无刷新新闻列表,下图所示的新闻列表相信大家并不少见,包括新闻的分页功能,本文要介绍的就是各分页间的切换方式。传统的方法
  • 左右结构是平常页面中最经常看到的结构,简洁一些的页面就会使用边框将左右两边隔开,但往往由于左右两边的内容可能是不等高的,所以就会有一高一低的
  • 以下的文章主要是介绍SQL Server数据库与其实际应用元数据,我前两天在相关网站看见SQL Server数据库与其实际应用元数据的资料,
  • l当今世界,技术发展迅猛,不论是什么行业,大多数关键数据都是放置于数据库中进行管理的,一来目前数据库技术已经相当成熟,二来其管理功能非常强大
  • 1.分析  我们在用 php 制作网站时,分类是很重要的,在分类下面又再分类这第二个分类称为次分类,而现在大多
  • 一个不错的网页拾色器也叫调色版,请看截图:当想要更多颜色时点击“其它颜色...”此时将调用系统自带的那个颜色选择框:注意:只有把〈scrip
  • 问题你想在使用范围内执行某个代码片段,并且希望在执行后所有的结果都不可见。解决方案为了理解这个问题,先试试一个简单场景。首先,在全局命名空间
  • 原文地址:30 Days of Mootools 1.2 Tutorials - Day 15 - SlidersMooTools 1.2的
  • 索引( Index )是常见的数据库对象,它的设置好坏、使用是否得当,极大地影响数据库应用程序和Database 的性能。虽然有许多资料讲索
  • isnull在数据库查询中的应用,特别是再语句连接的时候需要用到 比如连接时候,某个字段没有值但是又要左连接到其他表上 就会显示空, isn
  • instanceof 运算符 和 is_a() 方法都是判断:某对象是否属于该类 或 该类是此对象的父类(用于确定一个 PHP 变量是否属于
手机版 网络编程 asp之家 www.aspxhome.com