曲曲的秘密学术基地

纯化欲望、坚持严肃性

欢迎!我是曲泽慧(@zququ),目前在深圳(ICBI,BCBDI,SIAT)任职助理研究员。


病毒学、免疫学及结构生物学背景,可以在 RG 上找到我已发表的论文

本站自2019年7月已访问web counter

python 魔法方法 (8) 迭代器

整理自小甲鱼鱼C论坛

迭代器的详细解释

迭代器的意思类似于循环,每一次重复的过程被称为一次迭代的过程,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。提供迭代方法的容器被称为迭代器,通常接触的迭代器有序列(如列表、元组、字符)、字典等,它们都支持迭代的操作。

举个例子,通常使用for语句来进行迭代,

>>> for i in "FishC"
        print(i)

F
i
s
h
C

字符串就是一个容器,同时也是一个迭代器,for语句的作用就是触发这个迭代器的迭代功能,每次从容器里一次拿出一个数据,这就是迭代操作

但需要注意的是,迭代器不是一个容器,因为我们经常了解的容器像列表、字典、元组都是可以存放数据的,而迭代器就是实现了__next__()方法的对象(用于遍历容器中的数据)。

例2,字典和文件也是支持迭代操作的,

>>> links = {'鱼C工作室':'http://www.fishc.com', \
             '鱼C论坛':'http://bbs.fishc.com', \
             '鱼C博客':'http://blog.fishc.com', \}
>>> for each in links:
        print('%s -> %s' % (each, links[each]))

鱼C博客 -> http://www.fishc.com
鱼C论坛 -> http://bbs.fishc.com
鱼C工作室 -> http://blog.fishc.com

迭代器的两个BIF

关于迭代,Python提供了两个BIF: iter()next()

对于一个容器对象调用iter()得到它的迭代器,调用next()迭代器就会返回下一个值

迭代器的结束:如果迭代器没有值就可以返回了,并抛出StopInteration Error。

>>> string = "FishC"
>>> it = iter(string)  # iter() --> 获得了字符串容器的迭代器
>>> next(it)
'F'
>>> next(it)
'i'
...

>>> next(it)
'C'
>>> next(it)
StopIteration

我们利用while以及迭代器的两个BIF来分析for语句的工作方式:

>>> string = "FishC"
>>> it = iter(string)
>>> while True:
        try:
            each = next(it)
        except StopIteration:
            break
        print(each)

F
i
s
h
C

实现迭代器的两个魔法方法

实现迭代器的两个魔法方法有两个:__iter__()__next__()

方法 功能
__init__() 一个容器如果是迭代器,给方法实现返回迭代器本身
__next__() 决定迭代的规则
>>> class Fibs:
        def __init__(self):
            self.a = 0
            self.b = 1

        def __iter__(self):
            return self

        def __next__(self):
            self.a, self.b = self.b, self.a +self.b
            return self.a

>>> fibs = Fibs()
>>> for each in fibs:
        if each < 20:
            print(each)
        else:
            break

1
1
2
3
5
8
13

这个迭代器的唯一亮点就是没有终点,所以如果没有跳出循环,会不断迭代。可以通过修改__next__()来控制迭代的范围。

>>> class Fibs:
        def __init__(self, n=20):
            self.a = 0
            self.b = 1
            self.n = n

        def __iter__(self):
            return self

        def __next__(self):
            self.a, self.b = self.b, self.a + self.b
            if self.a > self.n:
                raise StopIteration
                return self.a

>>> fibs = Fibs(10)
>>> for each in fibs:
        print(each)

1
1
2
3
5
8

问题

问题(1) 用while语句实现与以下for语句相同的功能:

for each in range(5):
    print(each)

代码如下,

n = 0
list = []
list.append(n)
it = iter(list)
while n < 6:
    n += 1
    list.append(n)
    try:
        each = next(it)
    except StopIteration:
        break
    print(each)

答案代码,

alist = range(5)   # 直接用range()生成一个列表

while True:
    try:
        print(next(it))
    except StopIteration:
        break

问题(2) 写一个迭代器,要求输出至今为止所有的闰年。如:

>>> leapYears = LeapYear()
>>> for i in leapYears:
        if i >= 2000:
            print(i)
        else:
            break

2012
2008
2004
2000

提示:
闰年判定法
((year%4 == 0 and year%100! = 0)) or (year%400 == 0)

代码如下,

import datetime

class LeapYear():
    def __init__(self, n = datetime.date.today().year):
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):  
    # 注意的是__next__()方法总是描述下一次运行时即迭代中的单次行为。
        while (self.n % 400 != 0) and (self.n%4 != 0 and self.n%100 != 0):
            self.n = self.n - 1
        self.n -= 1
        return self.n+1  # return指令要在迭代描述的后面

leapYears = LeapYear()

for i in leapYears:
    if i >= 2000:
        print(i)
    else:
        break

答案代码如下,

import datetime as dt

class LeapYear:
    def __init__(self):
        self.now = dt.date.today().year

    def isLeapYear(self, year)
        if (year%4 == 0 and year%100 != 0) or (year%400 == 0):
            return True
        else:
            return False

    def __next__(self):
        while not self.isLeapYear(self.now):
            self.now -= 1

        temp = self.now
        self.now -= 1

        return temp
for i in leapYears:
    if i >= 2000:
        print(i)
    else:
        break

问题(3) 要求自己写一个MyRev类,功能与reversed()相同(内置函数reversed(seq)是返回一个迭代器,是序列seq的逆序显示)。例如:

>>> myRev = MyRev("FishC")
>>> for i in myRev:
    print(i, end='')

ChsiF

代码如下,

class MyRev():
    def __init__(self, seq):
        self.seq = seq
        self.len = len(seq)

    def seq2list(seq):
        list = []
        for i in seq:
            list.append(i)
        return list

    def __iter__(self):
        return self

    def __next__(self):
        temp = MyRev.seq2list(self.seq)
        if self.len == 0:
            raise StopIteration
        self.len -= 1
        # 这里可以直接return self.seq[self.len],即字符串可以当做列表使用
        return temp[self.len]

myRev = MyRev("FishC")
for i in myRev:
    print(i, end='')
Last One

数学分析 第一章 实数和数列极限

§ 1.1 实数 1.1.1 数轴的建立 1.1.2 建立数轴后引出的2个问题 § 1.2 无尽小数 § 1.3 收敛和收敛数列 1.3.1 极限的数学定义 1.3.2 几个结论及证明 § 1.4 收敛数列的性质 1.4.1 收敛数列极限的唯一性 1.4.2 数列的有界性质 1.4.3 子数列的性质 1.4.4 极限的运算性质 1.4.5 无穷...…

数学More
Next One

2020年,新年快乐

新年快乐现在是2020年的一月一日。新年来了,我的博客陪伴我走过了6个月的快乐时光。在翻看以前发的技术博文,每一个日期下的每一篇博文都有一段过往,可以是对过去的经历的回忆也可以是对未来的些许期许。2019年很长也很短,和以往的任何时间相比。但却又更加的具有意义,就像我虚度的每一年一模一样。新的一年里,我有很多愿望。不要停止自己追逐自己的脚步。加油!…

blogMore