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語句進行迭代,如何解決? '''javascript

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 kcss

輸出結構: 2 3 5 7 11 13 17 19 23 29html

解決方案: 將該類的iter方法實現成生成器函數,每次yield返回一個素數 '''html5

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)可產生序列 '''java

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個列表中, 同時迭代三個列表,計算每一個學生的總分.(並行)node

解決方案: 並行: 使用內置函數zip,它能將多個可迭代對象合併,每次迭代返回一個元組. '''python

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分人數.(串行)jquery

解決方案: 串行: 使用標準庫中的itertools.chain,它能將多個可迭代對象鏈接. '''linux

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
相關文章
相關標籤/搜索