python-哪些是可迭代对象?哪些是迭代器?迭代器和可迭代对象的区别——可迭代对象在遍历时不会发生消耗,但是迭代器会

一、迭代器和可迭代对象

1.1 哪些是可迭代对象?如何检测?

只要能用for x in X进行迭代的对象,都叫可迭代对象;检测一个对象是否是可迭代对象,可以用isinstace(seq, Iterable)语句,其中 Iterable类型在collections模块中,需要手动导入。

1.2 常见的可迭代对象、迭代器有哪些?

常见的可迭代对象,包括list, tuple, set, dict, ndarray等。

常见的迭代器,比如文件句柄对象,open()函数的返回值就是迭代器。

1.3 可迭代对象和迭代器的区别

可迭代对象不一定是迭代器,但是迭代器一定是可迭代对象;因此迭代器中包括可迭代对象没有的属性和方法,比如__next__(),这也导致迭代器可以传入next()而可迭代对象不行。

可迭代对象在遍历时不会发生消耗,但是迭代器是会发生消耗的;这句话很重要,是本文重点,也是全网文章中很少讲到的一个点。

二、对1.3中重点语句的进一步实验

2.1 文件对象中的read()、readline()、readlines()

本节主要参考以前我写的一篇文章

先创建一个txt文件,一共有5行。

当先将第一行的内容传给line后,打印出line,然后再直接用read()读完所有内容,下一次直接没办法迭代。 

with open('123.txt', 'r') as f:
    for line in f:
        print(line)
        print(f.read())
        print('Loop Ending.')
 
# ugyiqvqivew
 
# asaass
# sadasfa
# ggtrhtr
# adxzch
# Loop Ending.

而如果把read()注释掉,那么就会迭代5次,分别对应每一行。

with open('123.txt', 'r') as f:
    for line in f:
        print(line)
        # print(f.read())
        print('Loop Ending.')
 
# ugyiqvqivew
 
# Loop Ending.
# asaass
 
# Loop Ending.
# sadasfa
 
# Loop Ending.
# ggtrhtr
 
# Loop Ending.
# adxzch
# Loop Ending.

本节的结论:对于迭代器——文件句柄对象,我们可用for x in X来遍历它,每一次的遍历都会导致内容的消耗,当然也可以用read()、readline()、readlines()来遍历其中的内容。

2.2 对于迭代器,普遍可以用iter()、for x in X、islice()等方法遍历

上一节讲的是迭代器中的文件句柄对象可以用read()、readline()、readlines()来遍历;那么对于迭代器,普遍存在哪些方式去遍历其中内容呢?

2.2.1 循环遍历法——for x in X

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
    if i == 3:
        print(list(it))  # list函数会遍历完迭代器所有元素

# 1
# 2
# 3
# [4, 5, 6]

2.2.2 下一个遍历法——next()

list1 = [1,2,3,4,5,6]

it = iter(list1)

# next函数仅仅遍历迭代器的一个元素,调用一次消耗一次
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3

print(list(it))  # [4, 5, 6]

print(next(it))  # 因为上面已经遍历完了,所以再遍历就会出异常;Exception : StopIteration 

2.2.3 转换遍历法——list()、tuple()、set()、deque()、dict()

(1)转换成列表——list()

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
    if i == 3:
        print(list(it))  # list函数会遍历完迭代器所有元素

# 1
# 2
# 3
# [4, 5, 6]

(2)转换成元组——tuple()

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
    if i == 3:
        print(tuple(it))  # tuple函数会遍历完迭代器所有元素

# 1
# 2
# 3
# (4, 5, 6)

(3)转换成集合——set()

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
    if i == 3:
        print(set(it))  # set函数会遍历完迭代器所有元素

# 1
# 2
# 3
# {4, 5, 6}

(4)转换成队列——deque()

import collections

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
    if i == 3:
        print(collections.deque(it))  # deque函数会遍历完迭代器所有元素

# 1
# 2
# 3
# deque([4, 5, 6])

(5)转换成字典——dict()

list1 = [('a',1), ('b',2), ('c',3), ('d',4)]

it = iter(list1)

for i,t in enumerate(it):
    print(t)
    
    if i == 1:
        print(dict(it))  # dict函数会遍历完迭代器所有元素

# ('a', 1)
# ('b', 2)
# {'c': 3, 'd': 4}

2.2.4 切片遍历法——islice()

from collections import deque
import itertools
import numpy as np


iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
print(itertools.islice(it, None, 5, 2))  # 不用变量接收时,仅用print()无法完成遍历
print(list(it))  # [40, 30, 50, 46, 39, 44, 45, 67, 89, 34] ,因此输出的内容保留不变

iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
print(list(itertools.islice(it, None, 5, 2)))  # 不用变量接收时,但是用list完成了islice对象的遍历
print(list(it))  # [44, 45, 67, 89, 34] ,因此输出内容有所消耗

iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
print(tuple(itertools.islice(it, None, 5, 2)))  # 不用变量接收时,但是用tuple完成了islice对象的遍历
print(list(it))  # [44, 45, 67, 89, 34] ,因此输出内容有所消耗

iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
print(set(itertools.islice(it, None, 5, 2)))  # 不用变量接收时,但是用set完成了islice对象的遍历
print(list(it))  # [44, 45, 67, 89, 34] ,因此输出内容有所消耗

iterable = [('a',40), ('b',30), ('c',50), ('d',46)]
it = iter(iterable)
print(dict(itertools.islice(it, None, 5, 2)))  # 不用变量接收时,但是用dict完成了islice对象的遍历
print(list(it))  # [] ,因此输出内容有所消耗

iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
print(deque(itertools.islice(it, None, 5, 2)))  # 不用变量接收时,但是用deque完成了islice对象的遍历
print(list(it))  # [44, 45, 67, 89, 34]

# <itertools.islice object at 0x0000022F09409EA0>
# [40, 30, 50, 46, 39, 44, 45, 67, 89, 34]
# [40, 50, 39]
# [44, 45, 67, 89, 34]
# (40, 50, 39)
# [44, 45, 67, 89, 34]
# {40, 50, 39}
# [44, 45, 67, 89, 34]
# {'a': 40, 'c': 50}
# []
# deque([40, 50, 39])
# [44, 45, 67, 89, 34]

 切片遍历法有两种实施方式,要么直接转,要么先传给一个中间变量再转;前者在上面这一块代码,后者具体看下面的这块代码。

import itertools

# 情况1:start和stop都不是None,则在区间内的元素才被消耗
iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
d = itertools.islice(it, 2, 4)
print(list(d))   # [50, 46]
print(list(it))  # [39, 44, 45, 67, 89, 34]

# 情况2:stop是None,则所有元素都被消耗
iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
d = itertools.islice(it, 4, None, 2)
print(list(d))
print(list(it))  # []

# 情况3:start是None,则从一开头到stop区间中的元素被消耗
iterable = [40,30,50,46,39,44,45,67,89,34]
it = iter(iterable)
d = itertools.islice(it, None, 5, 2)
print(list(d))   # [40, 50, 39]
print(list(it))  # [44, 45, 67, 89, 34]

# [50, 46]
# [39, 44, 45, 67, 89, 34]
# [39, 45, 89]
# []
# [40, 50, 39]
# [44, 45, 67, 89, 34]

对于切片遍历法消耗内容的范围;如果stop设置为None,那么会遍历(消耗)所有元素;而如果start没设置为None,start往前的元素并不会被遍历(消耗)到。 详见上面的代码块。

2.3 哪些方法看起来能遍历但实际无法遍历?

2.3.1 print(iterator)函数无法遍历

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
# 1
# 2
# 3
# 4
# 5
# 6

2.3.2 numpy.array()或numpy.asarray()函数并无法遍历迭代器中的内容

import numpy as np

list1 = [1,2,3,4,5,6]

it = iter(list1)

for i in it:
    print(i)
    
    if i == 3:
        print(np.array(it))  # 返回的结果和不用np.array()的一样

# 1
# 2
# 3
# <list_iterator object at 0x0000022F08FA78E0>
# 4
# 5
# 6
  • 8
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值