python进阶——2. 对象迭代与反迭代技巧

2.1 迭代器和可迭代对象

迭代器是指继承自Iterator,并实现了next方法的对象。使用迭代器的好处是节省内存,每次计算取下一个值即可。

可迭代对象指继承自Iterable实现了iter方法的对象,能够通过for循环等方法进行迭代。实现让一个对象变成可迭代对象,可以通过iter返回其构造的迭代器对象。

import requests
from collections import Iterator, Iterable

class WeatherIterator(Iterator):
    def __init__(self, cities):
        self.cities = cities
        self.index = 0

    def get_weather(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):
        if self.index == len(self.cities):
            raise StopIteration
        city = self.cities[self.index]
        self.index += 1
        return self.get_weather(city)

class WeatherIterable(Iterable):
    def __init__(self, cities):
        self.cities = cities

    def __iter__(self):
        return WeatherIterator(self.cities)


if __name__ == "__main__":
    test_cities = ['北京', '沈阳', '成都', '上海']
    iterable = WeatherIterable(test_cities)
    print(iterable)
    for x in iterable:
        print(x)

2.2 生成器

生成器是另一种方式将一个对象转换成可迭代对象,其特殊的地方在于用yield代替return,将当前状态和返回值进行了保存,方便之后进行迭代。生成器的应用场景主要是计算出来的大量结果不需要放进内存中,而是可以通过迭代的方式更加高效地完成任务。

class PrimeNumbers:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def is_prime(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.is_prime(k):
                yield k

if __name__ == "__main__":
    prime = PrimeNumbers(0, 10)
    for x in prime:
        print(x)

2.3 反向迭代

对一个序列进行反向迭代,例如a = [1, 2, 3, 4],反向迭代变成[4, 3, 2, 1]。
方法有很多,a.reverse()方法可以反向迭代但是改变了a的值;a[::-1]通过列表切片可以反向迭代但是是生成了一个新的列表。
其实较好的操作是使用全局函数reversed(a),其生成了反向的迭代器对象,与iter(a)作用相似,只不过iter方法返回的是正向的迭代器。

class FroatRange:
    def __init__(self, start, end, step):
        self.start = start
        self.end = end
        self.step = step

    def __iter__(self):
        a = self.start
        while a <= self.end:
            yield a
            a += self.step

    def __reversed__(self):
        a = self.end
        while a >= self.start:
            yield a
            a -= self.step

if __name__ == "__main__":
    froat = FroatRange(0, 3, 0.5)
    for x in iter(froat):
        print(x)
    for y in reversed(froat):
        print(y)

2.4 对迭代器进行切片操作

如何将一个迭代器像一个list或者字符串那样进行切片操作,可以使用itertools的islice

from itertools import islice

a = range(0, 10)
t = iter(a)
for x in islice(t, 0, 5):
    print(x)

但是,如果使用了islice方法,会消耗t迭代器,意思就是说,当使用了islice进行切片操作,t也迭代到了对应位置上。

from itertools import islice

a = range(0, 10)
t = iter(a)
for x in islice(t, 0, 5):
    print(x)
print("========================")
for y in t:
    print(y)

其中,第二次迭代t,起始位置就变成了5.

2.5 使用for语句迭代多个对象

比较简单的做法是通过for循环可迭代对象的长度,然后根据索引迭代多个对象。此做法有些局限性,比如生成器是无法做到迭代长度的。

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

for index in range(len(a)):
    print(a[index])
    print(b[index])

比较通用的方法是使用zip函数,将多个可迭代对象分别取出对应索引的值,组成一个元组,然后包装城一个迭代器。

print(zip(a, b))
for x in zip(a, b):
    print(x)

(1, 'a')
(2, 'b')
(3, 'c')
(4, 'd')

所以,迭代多个对象语句就变成了:

for x, y in zip(a, b):
    print(x)
    print(y)

上面属于并行迭代多个对象,还有一种情况是串行迭代多个对象。可以使用itertools的chain方法。

from itertools import chain
for x in chain(a, b):
    print(x)

这样,a和b就是按照顺序串行迭代。

你可能感兴趣的:(python进阶——2. 对象迭代与反迭代技巧)