首页 > 解决方案 > 为什么 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))

标签: pythonpython-3.xtypesgenerator

解决方案


根据文档_GeneratorType

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)都会返回一个基于相同底层迭代器的迭代


推荐阅读