关于检查对象是否为 Python 中的迭代器的示例的混淆

Confusion about one example to check if an object is an iterator in Python

我在 Whosebug 上阅读了一些关于如何在 Python 中检查对象是否为迭代器的帖子,但它们似乎没有解决我的问题。我从书中有这个例子有效Python

def normalize_defensive(numbers):
   if iter(numbers) is iter(numbers):  # An iterator — bad!
       raise TypeError(‘Must supply a container’)
   total = sum(numbers)
   result = []
   for value in numbers:
       percent = 100 * value / total
       result.append(percent)
   return result

使用:

visits = [15, 35, 80]
normalize_defensive(visits)  # No error
visits = ReadVisits(path)  # ReadVisits is a class with an __iter__ method.
normalize_defensive(visits)  # No error
it = iter(visits)
normalize_defensive(it)
>>>
TypeError: Must supply a container

所以我的问题在这一行:

if iter(numbers) is iter(numbers):  # An iterator — bad!

为什么这一行要检查变量 numbers 是否是一个迭代器?当 visits = [15, 35, 80] 时,iter(numbers) is iter(numbers) 应该是真的吗?

当您调用 iterable 时,对此类对象调用 iter() 将始终生成 new 迭代器对象。但是在 迭代器 上调用 iter() 将始终 return 相同的对象;这是 iterator protocol 的要求。

来自iterator.__iter__() documentation

Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements.

因为iter(iterable)总是returns 自身,所以测试iter(obj) is iter(obj)会为真;在这两种情况下,同一个对象被 returned。

为了帮助您理解 Martijn 的解释,请看以下内容:

>>> numbers = [15, 35, 80]
>>> it  = iter(numbers)
>>> it2 = iter(numbers)
>>> it3 = iter(it)
>>> id(it1)
51123792
>>> id(it2)
51056464    # id of it2 is different from it1
>>> id(it3) 
51123792    # iterator of iterator it3 has the same id as iterator it1

因此,如果 numbers 是一个 iterator,在 numbers 上调用 iter 将始终 return 个内部相同的对象:iter(numbers) is iter(numbers)将是 True.