python - 为什么 enumerate、zip、range 类型不属于 types.GeneratorType?
问题描述
Python 3 引入了类似生成器的对象,以便在调用range()
和时返回zip()
。返回的对象就像一个生成器,可以迭代一次,但不能很好地“打印”,就像enumerate()
返回参数一样。
然而,我很困惑地看到它们是不同的对象类型并且不属于types.GeneratorType
,或者至少这是types
模块显示的内容。将运行的函数(例如,期望生成器)不会检测到它们。他们的遗产是什么?它们是否属于主要的“生成器”结构,以便可以与其他生成器一起识别它们?
import types
a = [1,2,3]
b = [4,5,6]
# create some generator-type objects
obj_zip = zip(a,b)
obj_enu = enumerate(a)
obj_r = range(10)
print(type(obj_zip))
print(type(obj_enu))
print(type(obj_r))
# checking against types.GeneratorType returns False
print(isinstance(obj_zip,types.GeneratorType))
print(isinstance(obj_enu,types.GeneratorType))
print(isinstance(obj_r,types.GeneratorType))
# checking against their own distinct object types returns True
print(isinstance(obj_zip,zip))
解决方案
types.GeneratorType
生成器-迭代器对象的类型,由生成器函数创建。
生成器函数是语言中的特定事物;它表示使用yield
或的函数yield from
(或生成器表达式,它们只是内联生成器函数的简写)。它是迭代器集的子集(您可以调用以获取新值的所有事物),而后者又是可迭代对象的子集(您可以调用以获取迭代器的next()
所有事物;迭代器本身就是可迭代对象,其中表现为恒等函数)。iter()
iter(iterator)
基本上,如果您正在测试“我可以循环这个吗?”,请测试isinstance(obj, collections.abc.Iterable)
。如果您正在检查“这是一个可耗尽的迭代器吗?” (也就是说,我会通过循环来耗尽它吗?),测试或者测试isinstance(obj, collections.abc.Iterator)
基于鸭子类型的方法,测试iter(obj) is obj
(迭代器上的不变量要求产生iter(iterator)
原始迭代器对象不变)。
请注意,range
它不是生成器或迭代器。根据文档:
range 实际上不是一个函数,而是一个不可变的序列类型,如Ranges and Sequence Types — list, tuple, range中所述。
作为一个不可变的序列类型意味着它是一个可迭代的,但仅此而已。它通常用作迭代器的事实是无关紧要的。如果它是一个迭代器,这里的第二个循环将永远不会执行:
r = range(3)
for i in r:
print("First", i)
for i in r:
print("Second", i)
但它工作得很好,因为每个(隐式)调用iter(r)
都会返回一个基于相同底层迭代器的新迭代器。
推荐阅读
- android - Flutter:关于命名和初始路由的问题
- python - 给定列表中存在的元素,如何返回包含任何元素出现次数的列表?
- javascript - 选择复选框时遇到问题
- c++ - 在动态数组中为字符串类型崩溃实现擦除
- annotation-processing - 在我项目的源码包下生成java源码
- swift - 如何在 SwiftUI 中的表单段上添加填充
- python - 为正则表达式查找长度为 0 - 4 的所有单词(方法?)
- javascript - 函数中的for循环只循环一次
- python - 在熊猫中如何使用 drop_duplicates 有一个例外?
- ruby - Ruby 循环 | 硒 | 网络测试