Python3.1中的视图究竟是什么?它们的行为似乎与迭代器的行为类似,它们也可以实现为列表。迭代器和视图有何不同?
答案 0 :(得分:12)
据我所知,视图仍然附加到它创建的对象上。对原始对象的修改会影响视图。
来自docs的(对于字典视图):
>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.keys()
>>> values = dishes.values()
>>> # iteration
>>> n = 0
>>> for val in values:
... n += val
>>> print(n)
504
>>> # keys and values are iterated over in the same order
>>> list(keys)
['eggs', 'bacon', 'sausage', 'spam']
>>> list(values)
[2, 1, 1, 500]
>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> del dishes['sausage']
>>> list(keys)
['spam', 'bacon']
>>> # set operations
>>> keys & {'eggs', 'bacon', 'salad'}
{'bacon'}
答案 1 :(得分:5)
我建议您阅读this。它似乎做了最好的解释。
据我所知,视图似乎与dict
s更相关,可以强制进入list
s。你也可以用它们创建一个迭代器,然后通过它迭代(在for
循环中或通过调用next
)
答案 2 :(得分:1)
迭代器和视图有何不同?
我将这个问题改为“ iterable 对象与迭代器”之间有什么区别?
iterable 是一个可以迭代的对象(例如在for
循环中使用)。
迭代器是一个可以使用next()
函数调用的对象,即它在Python2中实现.next()
方法,在python3中实现.__next__()
。迭代器通常用于包装 iterable 并返回每个感兴趣的项目。所有迭代器都是可迭代的,但反过来不一定是真的(所有迭代都不是迭代器)。
视图是可迭代的对象,而不是迭代器。
让我们看一些代码来看看区别(Python 3):
"What's new in Python 3"文档非常具体地说明哪些函数返回迭代器。 map()
,filter()
和zip()
肯定会返回一个迭代器,而dict.items()
,dict.values()
,dict.keys()
则会返回一个视图对象。至于range()
,虽然它返回的描述完全缺乏精确性,但我们知道它不是迭代器。
使用map()
加倍列表中的所有数字
m = map(lambda x: x*2, [0,1,2])
hasattr(m, '__next__')
# True
next(m)
# 0
next(m)
# 2
next(m)
# 4
next(m)
# StopIteration ...
使用filter()
提取所有奇数
f = filter(lambda x: x%2==1, [0,1,2,3,4,5,6])
hasattr(f, '__next__')
# True
next(f)
# 1
next(f)
# 3
next(f)
# 5
next(f)
# StopIteration ...
尝试以相同的方式使用range()
来生成数字序列
r = range(3)
hasattr(r, '__next__')
# False
next(r)
# TypeError: 'range' object is not an iterator
但它是一个可迭代的,所以我们应该能够用迭代器
来包装它it = iter(r)
next(it)
# 0
next(it)
# 1
next(it)
# 2
next(it)
# StopIteration ...
dict.items()
以及dict.keys()
和dict.values()
也不会在Python 3中返回迭代器
d = {'a': 0, 'b': 1, 'c': 2}
items = d.items()
hasattr(items, '__next__')
# False
it = iter(items)
next(it)
# ('b', 1)
next(it)
# ('c', 2)
next(it)
# ('a', 0)
迭代器只能在单个for
循环中使用,而迭代可以在后续for
循环中重复使用。每次在此上下文中使用iterable时,它都会隐式返回一个新的迭代器(来自其__iter__()
方法)。以下自定义类通过输出列表对象和返回迭代器对象的内存id
来演示此内容:
class mylist(list):
def __iter__(self, *a, **kw):
print('id of iterable is still:', id(self))
rv = super().__iter__(*a, **kw)
print('id of iterator is now:', id(rv))
return rv
l = mylist('abc')
for
循环可以使用iterable对象,并隐式获取迭代器
for c in l:
print(c)
# id of iterable is still: 139696242511768
# id of iterator is now: 139696242308880
# a
# b
# c
后续的for
循环可以使用相同的可迭代对象,但会得到另一个迭代器
for c in l:
print(c)
# id of iterable is still: 139696242511768
# id of iterator is now: 139696242445616
# a
# b
# c
我们也可以显式获取迭代器
it = iter(l)
# id of iterable is still: 139696242511768
# id of iterator is now: 139696242463688
但它只能使用一次
for c in it:
print(c)
# a
# b
# c
for c in it:
print(c)
for c in it:
print(c)