Python对象迭代与反迭代相关问题与解决技巧

 

1.如何实现可迭代对象和迭代器对象(1)

In [1]:
# 列表和字符串都是可迭代对象

l = [1,2,3,4]
In [2]:
s = 'abcde'
In [3]:
for x in l:print(x)
 
1
2
3
4
In [4]:
for x in s:print(x)
 
a
b
c
d
e
In [5]:
iter(l)
Out[5]:
<list_iterator at 0x7fde5571c208>
In [6]:
iter(s)
Out[6]:
<str_iterator at 0x7fde5571c710>
In [7]:
l.__iter__()
Out[7]:
<list_iterator at 0x7fde5571ca90>
In [8]:
# 迭代器对象

t = iter(l)
In [9]:
next(t)
Out[9]:
1
In [10]:
next(t)
Out[10]:
2
In [11]:
next(t)
Out[11]:
3
In [12]:
t2 = iter(s)
In [13]:
next(t2)
Out[13]:
'a'
In [14]:
next(t2)
Out[14]:
'b'
 

2.如何实现可迭代对象和迭代器对象(2)

 

''' 从网络抓取各个城市气温,并依次显示: 北京:12-16 上海:20-30 ... 如果一次抓取所有城市天气再显示,显示第一个城市气温时,有很高的延时,并且浪费存储空间,我们期望以'用时访问的策略', 并且能把所有城市气温封装到一个对象里,可用for语句进行迭代,如何解决? '''

In [15]:
import requests

def getWeather(city):
    '''获取一个城市气温'''
    r = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=' + city)
    data = r.json()['data']['forecast'][0]
    
    return '%s:%s,%s' %(city,data['low'],data['high'])
In [16]:
getWeather('北京')
Out[16]:
'北京:低温 -7℃,高温 0℃'
In [17]:
getWeather('上海')
Out[17]:
'上海:低温 8℃,高温 10℃'
In [18]:
from collections import Iterable,Iterator
In [19]:
# 可迭代对象抽象接口
Iterable.__abstractmethods__
Out[19]:
frozenset({'__iter__'})
In [20]:
# 迭代器对象抽象接口
Iterator.__abstractmethods__
Out[20]:
frozenset({'__next__'})
In [21]:
import requests
from collections import Iterable,Iterator

class WeatherIterator(Iterator):
    '''实现一个迭代器对象WeatherIterator'''
    def __init__(self,cities):
        self.cities = cities
        #记录迭代位置
        self.index = 0
    
    def getWeather(self,city):
        '''获取单个城市气温数据'''
        r = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=' + city)
        data = r.json()['data']['forecast'][0]
        return '%s:%s,%s' %(city,data['low'],data['high'])
        
    def __next__(self):
        '''__next__方法每次返回一个城市气温'''
        if self.index == len(self.cities):
            raise StopIteration
        city = self.cities[self.index]
        self.index += 1
        return self.getWeather(city)
    
class WeatherIterable(Iterable):
    '''实现一个可迭代对象WeatherIterable'''
    def __init__(self,cities):
        self.cities = cities
        
    def __iter__(self):
        '''__iter__方法返回一个迭代器对象'''
        return WeatherIterator(self.cities)
In [22]:
for city in WeatherIterable(['北京','上海','广州','深圳']):
    print(city)
 
北京:低温 -7℃,高温 0℃
上海:低温 8℃,高温 10℃
广州:低温 9℃,高温 13℃
深圳:低温 12℃,高温 15℃
 

3.如何使用生成器函数实现可迭代对象

 

''' 实际案例: 实现一个可迭代对象的类,它能迭代出给定范围内的所有素数: pn = PrimeNumber(1, 30) for k in pn: print k

输出结构: 2 3 5 7 11 13 17 19 23 29

解决方案: 将该类的iter方法实现成生成器函数,每次yield返回一个素数 '''

In [23]:
def f():
    print('in f(),1')
    yield 1
    
    print('in f(),2')
    yield 2
    
    print('in f(),3')
    yield 3
    
g = f()

print(g.__next__())
print(g.__next__())
print(g.__next__())
 
in f(),1
1
in f(),2
2
in f(),3
3
In [24]:
'''生成器对象即实现了可迭代对象接口,又实现了迭代器接口'''

g = f()
for x in g:
    print(x)
 
in f(),1
1
in f(),2
2
in f(),3
3
In [25]:
g.__iter__() is g
Out[25]:
True
In [26]:
# 使用生成器返回所有素数

class PrimeNumbers:
    def __init__(self,start,end):
        self.start = start
        self.end = end
        
    def isPrimeNum(self,k):
        if k < 2:
            return False
        
        for i in range(2,k):
            if k % i == 0:
                return False
        return True
    
    def __iter__(self):
        for k in range(self.start,self.end+1):
            if self.isPrimeNum(k):
                yield k
In [27]:
for x in PrimeNumbers(1,100):
    print(x)
 
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
 

4.如何进行反向迭代以及如何实现反向迭代

 

''' 实际案例: 实现一个连续浮点数发生器FloatRange(和xrange类似), 根据给定范围(start, end)和步进值(step)产生一系列连续浮点数, 如迭代FloatRange(3.0, 4.0, 0.2)可产生序列 '''

In [28]:
l = [1,2,3,4,5]
In [29]:
l.reverse()# 会改变原列表
In [30]:
# 切片操作,返回新的列表,但是浪费资源
l1 = l[::-1]
In [31]:
# 列表的反向迭代器,与iter()对应
reversed(l)
Out[31]:
<list_reverseiterator at 0x7fde55721358>
In [32]:
for x in reversed(l):
    print(x)
 
1
2
3
4
5
In [33]:
# 实现正向和反向连续浮点序列
class FloatRange:
    def __init__(self,start,end,step=0.1):
        self.start = start
        self.end = end
        self.step = step
        
    #正向迭代器
    def __iter__(self):
        t = self.start
        while t<= self.end:
            yield t
            t += self.step
            
    #反向迭代器   
    def __reversed__(self):
        t = self.end
        while t >= self.start:
            yield t
            t -= self.step
In [34]:
for x in FloatRange(1.0,4.0,0.5):
    print(x)
 
1.0
1.5
2.0
2.5
3.0
3.5
4.0
In [35]:
for x in reversed(FloatRange(1.0,4.0,0.5)):
    print(x)
 
4.0
3.5
3.0
2.5
2.0
1.5
1.0
 

5.如何对迭代器做切片操作

In [36]:
f = open('Alice.txt')
In [37]:
ls_lines = f.readlines()
# 会把文件指针移动到了文件最后
cut_lines = ls_lines[1:5]
print(cut_lines)
# readlines会把整个文件导入到内存当中,文件过大时会出现内存不足
 
['she hadpeeped into the book her sister was reading, but it had nopictures or conversations in it, `and what is the use \n', "of a book,'thought Alice `without pictures or conversation?'So she was considering in her own mind (as well as she \n", 'could,for the hot day made her feel very sleepy and stupid), whetherthe pleasure of making a daisy-chain would be worth \n', 'the troubleof getting up and picking the daisies, when suddenly a WhiteRabbit with pink eyes ran close by her.There was \n']
In [38]:
# islice能返回一个迭代对象切片的生成器
from itertools import islice

islice(f,100,300)
Out[38]:
<itertools.islice at 0x7fde54cdcf48>
In [39]:
f.seek(0)# 把文件指针移动到文件最前
for line in islice(f,20,25):
    print(line)
 
Alice to herself, `after such a fall as this, Ishall think nothing of tumbling down stairs!  How brave they'llall think 

me at home!  Why, I wouldn't say anything about it,even if I fell off the top of the house!' (Which was very 

likelytrue.)Down, down, down.  Would the fall NEVER come to an end!  `Iwonder how many miles I've fallen by this time?' 

she said aloud.`I must be getting somewhere near the centre of the earth.  Letme see:  that would be four thousand 

miles down, I think--' (for,you see, Alice had learnt several things of this sort in herlessons in the schoolroom, and 

In [40]:
islice(f,30)#前30行
islice(f,50,None)#50-最后一行
Out[40]:
<itertools.islice at 0x7fde54cca598>
In [41]:
l = range(20)
In [42]:
#生成l的迭代器
t = iter(l)
In [43]:
#每次使用islice时,要重新申请一个可迭代对象,它会消耗这个迭代对象的资源
for x in islice(t,5,10):
    print(x)
 
5
6
7
8
9
In [44]:
#t已经迭代到位置10
for x in t:
    print(x)
 
10
11
12
13
14
15
16
17
18
19
 

6.如何在一个for语句中迭代多个可迭代对象

 

''' 实际案例: 1.某班学生期末成绩,语文,数学,英语分别存储在3个列表中, 同时迭代三个列表,计算每个学生的总分.(并行)

解决方案: 并行: 使用内置函数zip,它能将多个可迭代对象合并,每次迭代返回一个元组. '''

In [45]:
from random import randint

chinese = [randint(60,100) for _ in range(40)]
math = [randint(60,100) for _ in range(40)]
english = [randint(60,100) for _ in range(40)]
In [46]:
# 使用索引
# 局限:如果不是列表,而是生成器的话,将不能用索引访问
t = []
for i in range(len(chinese)):
    t.append(chinese[i] + math[i] + english[i])
    
print(t)
 
[211, 198, 246, 238, 237, 244, 263, 217, 242, 226, 266, 238, 272, 249, 249, 222, 221, 265, 249, 234, 216, 213, 245, 236, 243, 239, 253, 244, 239, 264, 226, 231, 246, 255, 245, 236, 221, 229, 249, 217]
In [47]:
# 使用zip()函数
total = []
for c,m,e in zip(chinese,math,english):
    total.append(c + m + e)
    
print(total)
 
[211, 198, 246, 238, 237, 244, 263, 217, 242, 226, 266, 238, 272, 249, 249, 222, 221, 265, 249, 234, 216, 213, 245, 236, 243, 239, 253, 244, 239, 264, 226, 231, 246, 255, 245, 236, 221, 229, 249, 217]
 

''' 实际案例: 2.某年及有4个班,某次考试每班英语成绩分别存储在4个列表中, 依次迭代每个列表,统计全学年成绩高于90分人数.(串行)

解决方案: 串行: 使用标准库中的itertools.chain,它能将多个可迭代对象连接. '''

In [48]:
from random import randint
from itertools import chain


c1 = [randint(60,100) for _ in range(40)]
c2 = [randint(60,100) for _ in range(41)]
c3 = [randint(60,100) for _ in range(42)]
c4 = [randint(60,100) for _ in range(43)]

count = 0

for s in chain(c1,c2,c3,c4):
    if s > 90:
        count += 1
In [49]:
count
Out[49]:
37

猜你喜欢

转载自www.cnblogs.com/prince5460/p/10097915.html