零基础入门学习Python(25):魔法方法(5)定制序列和迭代器

零基础入门学习Python(25):魔法方法(5)定制序列和迭代器

容器类型的协议
如果希望定制不可变的容器,则需要定义__len__(self)和__getitem__(self,key)方法;如果希望定制的容器是可变的,则除了要定义上面两个方法,还需要定义__setitem__(self,key,value)和__delitem__(self,key)方法。
其中,__len__(self)定义当被 len() 调用时的行为;
__getitem__(self,key)定义获取容器中指定元素的行为,相当于self[key];
__setitem__(self,key,value)定义设置容器中指定元素的行为,相当于self[key] = value;
__delitem__(self,key)定义删除容器中指定元素的行为,相当于del self[key]

下面举例通过编写一个不可变的自定义列表来记录列表中每个元素被访问的次数,熟悉不可变容器的定制。

>>> class CountList:
        def __init__(self, *args):            #参数是可变数量的
            self.values = [x for x in args]   #利用列表推导式初始化value
            self.count = {}.fromkeys(range(len(self.values)),0)    #字典类型,初始化所有索引对应的值得被访问次数为为0
        def __len__(self):
            return len(self.values)
        def __getitem__(self, key):
            self.count[key] += 1              #指索引k对应的值的个数加一
            return self.values[key]           #返回索引对应的值

>>> c1 = CountList(1,3,5,7,9)                 #生成两个实例对象
>>> c2 = CountList(2,4,6,8,10)
>>> c1[1]                                     #第一次访问c1的索引1对应的值
3
>>> c2[1]                                     #第一次访问c2的索引1对应的值
4
>>> c1[1] + c2[1]                             #第二次访问c1[1]和c2[1]
7
>>> c1.count                                  #查看对象的count属性,则索引1对应的访问次数为2
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
>>> c2.count
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
>>> c1[1]
3
>>> c1.count                                  #再访问一次c1[1]之后,看到其对应的次数加1
{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}

可变容器的定制留给大家自己练习。
在魔法方法的最后,我们介绍一下迭代器。
iter():对一个容器对象(序列(列表,元组,字符串),字典,文件)调用 iter() 就得到一个迭代器,调用next(),迭代器就会返回下一个值,如果迭代器没有值返回了,Python就会抛出一个StopIteration的异常

>>> string = "Jessica"
>>> it = iter(string)                 #it是一个迭代器
>>> next(it)                          #注意next的用法,返回迭代器it的下一个值
'J'
>>> next(it)
'e'
>>> next(it)
's'
>>> next(it)
's'
>>> next(it)
'i'
>>> next(it)
'c'
>>> next(it)
'a'
>>> next(it)                          #迭代器没有值调用next会抛出一个StopIteration异常
Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    next(it)
StopIteration
>>> it = iter(string)                  #重新定义一个迭代器
>>> while True:                        #利用异常处理语句输出迭代器
        try:
            each = next(it)
        except StopIteration:
            print("There is no more data.")
            break;
        print(each)

J
e
s
s
i
c
a
There is no more data.

迭代器的魔法方法
__iter__(self):返回迭代器本身,即 return self ;
__next__():决定了迭代器的迭代规则;

>>> class Fibs:                          #定义一个类,输出斐波那契数
        def __init__(self, n = 10):      #初始化有默认值,即输出不大于n的斐波那契数
            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:          #如果产生大于n的斐波那契数,则抛出异常,否则返回斐波那契数
                raise StopIteration
            return self.a

>>> fibs = Fibs()                        #产生不大于10的斐波那契数
>>> for each in fibs:
        print(each)

1
1
2
3
5
8
>>> fibs = Fibs(100)                     #产生不大于100的斐波那契数
>>> for each in fibs:
        print(each)

1
1
2
3
5
8
13
21
34
55
89

零基础入门学习Python(24):魔法方法(4)描述符

你可能感兴趣的:(python,迭代器,容器,next)