python之彻底搞懂迭代、可迭代、迭代器的区别(三)

可迭代对象常见的有str、list、tuple、dict等,对这些容器访问其内部元素时可以用“对象[下标]”的方式。实际上是因为python对这些对象封装了getitem方法,以下通过斐波那契数列类的案例来了解getitem的定义方法。

表面可迭代对象

class Fib(object):
    # count表示生成斐波那契数列的个数
    def __init__(self, count):
        self.count = count
        # 保存前两个值
        self.x = 0
        self.y = 1
        # 记录生成数列的下标

    # 声明Fib类是可迭代的
    def __iter__(self):
        return self

    def __getitem__(self, item):
        if isinstance(item, int):
            if item <= self.count:
                self.x = 0
                self.y = 1
                for x in range(item):
                    result = self.x
                    self.x, self.y = self.y, self.x + self.y
                return result
            else:
                raise TypeError('超出范围!')
        elif isinstance(item, slice):
            start, stop = item.start, item.stop
            l = []
            self.x = 0
            self.y = 1
            for x in range(stop):
                if x >= start:
                    l.append(self.x)
                self.x, self.y = self.y, self.x + self.y
            return l
        else:
            raise TypeError('参数不合要求!')


fib6 = Fib(6)
print(fib6[0:5])
print(fib6[6])

            
out:
[0, 1, 1, 2, 3]
5

python解释器在遇到对象后跟方括号[]取值时,会调用该对象的getitem方法,若要赋值调用setitem方法,若要删除调用delitem方法。

实际上上述代码存在缺陷,表面是可迭代对象,实际是迭代器,因为每个元素都是实时生成的,而且不能对其修改。若尝试fib6[2]=5会报错。

真正可迭代对象

class Fib(object):
    # count表示生成斐波那契数列的个数
    def __init__(self, count):
        self.count = count
        self.x = 0
        self.y = 1
        self.index = 0
        self.row = []
        for x in range(self.count):
            self.row.append(self.x)
            self.x, self.y = self.y, self.x + self.y
            self.index += 1

    # 声明Fib类是可迭代的
    def __iter__(self):
        return self

    def __getitem__(self, item):
        if isinstance(item, int):
            if item <= self.count:
                return self.row[item]
            else:
                raise TypeError('超出范围!')
        elif isinstance(item, slice):
            start, stop = item.start, item.stop
            return self.row[start:stop]
        else:
            raise TypeError('参数不合要求!')

    def __setitem__(self, item, value):
        if isinstance(item, int):
            if item <= self.count:
                self.row[item] = value
            else:
                raise TypeError('超出范围!')
        else:
            raise TypeError('参数不合要求!')


fib6 = Fib(6)
print(fib6[:4])
fib6[2] = 5
print(fib6[:4])

out:
[0, 1, 1, 2]
[0, 1, 5, 2]

上述代码是真正的可迭代对象,因为每个元素都是保存在列表中,可以对其修改,例如尝试fib6[2]=5不会报错。

注:以上代码对slice第三参数未处理,修改值时也只能一个个改,但不影响深入理解可迭代对象。

总结

通过代码比较可以帮助我们更深入理解可迭代对象,现在对可迭代对象与迭代器的特点做比较会很容易理解了。

  • 可迭代对象内部元素是一次生成,全部存在命名空间内。迭代器内部元素是访问一次生成一次。
  • 可迭代对象常用的字符串、列表、字典、集合等python封装了很多方法。python对迭代器封装的方法较少。
  • 可迭代对象内部元素的值可以修改(列表和字典)。迭代器内部元素的值只能读不能改。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值