python面向对象编程(4)

来源:互联网 发布:sql 优化方面的书籍 编辑:程序博客网 时间:2024/06/07 07:02
python重载运算符详解
  1. 基础

    • 运算符重载能够让类拦截正常的python操作
    • 类能够重载所有的python表达式操作
    • 类也能够重载内置操作,如打印、函数调用抑或是属性访问
    • 重载能够让类的实例看上去更像是内置类型
    • 重载是实现类中提供的特殊方法名,如__X__
  2. 索引和切片操作,__getitem__ & __setitem__

    • __getitem__方法被调用的应用场景

对象实例根据索引值获取索引值对应的数据

# indexer.pyclass Indexer:    def __init__(self):        print("call init ...")        self.__data = [1,2,3]    def __getitem__(self, index):           # index为索引值        print("call getitem index...")        return self.__data[index]def test_index():    # 取值    for i in range(3):    print(X[i])  # 等价于Indexer.__getitem__(X,i)if __name__ == '__main__':    test_index()>>> python indexer.py   # 注:python如果没有说明表示都是3.x版本

这里写图片描述

对象实例根据分片方式获取一组分片索引值对应的数据

# slice.pyclass SliceObject:    def __init__(self):        print("call slice object init ...")        self.__data = [1,2,3,4,5,6    ]    def __getitem__(self, index):   # index为索引值或者分片对象        if isinstance(index, int):            print('indexing', index)        else:            # 分片对象有start stop 以及step属性            print('slicing', index.start, index.stop, index.step)        return self.__data[index]def test_slice():    X = SliceObject()    # 分片取值    print(X[0:2])    print(X[:-1])    print(X[1:])if __name__ == '__main__':    test_slice()>>> python slice.py

这里写图片描述

迭代器调用并进行数据遍历

# indexer.py def test_iterator():    X = Indexer()    for item in X:        print(item)if __name__ == '__main__':    # test_index()    test_iterator()>>> python indexer.py

这里写图片描述

py2.x分片操作的内置方法,py3.x已经删除

# slice.py class Slicer:    """    py2.x 分片    """    def __getitem__(self, index):        print("call __getitem__ for index:%s" % str(index))    def __getslice__(self, i, j):        print("call __getslice__ for start[%d] to end[%d]" % (i,j))    def __setslice__(self, i, j, seq):        print("call __setslice__ for start[%d] to end[%d] with seq[%d]" % (i,j,seq))def test_slicer():    Slicer()[1]    Slicer()[1:9]    Slicer()[1:9:2]if __name__ == '__main__':    test_slicer()>>> python slice.py

这里写图片描述

这里写图片描述

py3.x新增__index__内置方法,该方法表示返回一个实例对象的整数型,与索引切片没关系

# indexer.pyclass Indexing:    """py3.x 新增的内置方法,但是该操作不是表示索引操作,而是为一个对象实例返回一个整型数值,并且用于转换为数值字符串的内置操作    """    def __index__(self):        return 200def test_indexing():    X = Indexing()    # 将对象转换为数值字符串,这里执行两个内置方法,__index__ 和 __str__    print(hex(X))if __name__ == '__main__':    test_indexing()>>> python indexer.py

这里写图片描述

  • __setitem__对索引属性进行赋值操作
# indexer.pyclass Indexer:    ...     def __setitem__(self, index, value):    # index恒为索引下标,value为值        print("call setitem ...")        print("key[%s]--value[%s]" % (index,value))        self.__data.insert(index,value)def test_index():    # 设置值    X = Indexer()    X[0] = 1  # 等价于Indexer.__setitem__(X,0,1)if __name__ == '__main__':    test_index()>>> python indexer.py

这里写图片描述
3. 迭代器对象:__iter__ & __next__

自定义迭代器

# iterator.pyclass Squares:    def __init__(self, start, stop):        self.value = start - 1        self.stop = stop    def __iter__(self):        # 生成迭代器对象        print("call iter ...")        return self    def __next__(self):        if self.value == self.stop:            raise StopIteration        print("call next for value:", end='')        self.value += 1        return self.value ** 2def test():    X = Squares(1, 5)    # 迭代器不支持使用索引    X[1]    # TypeError: 'Squares' object does not support indexingif __name__ == '__main__':    test()>>> python iterator.py

这里写图片描述

使用循环迭代器

# iterator.pydef test_for():    # 循环使用迭代器    for item in Squares(2, 9):  # 调用Squares.__iter__,生成迭代器对象        print(item)             # 调用Squares.__next__>>> python iterator.py

这里写图片描述

逐个进行迭代

# iterator.pydef test_single():    # 逐个调用迭代器    X = Squares(2, 9)    # 显示将X转换为迭代器对象,条件是该对象有实现__iter__,只需调用一次    I = iter(X)             # Squares.__iter__    print(next(I))          # 调用Squares.__next__    print(next(I))          # 调用Squares.__next__if __name__ == '__main__':    test_single()>>> python iterator.py

这里写图片描述

迭代器单次扫描

# iterator.pydef single_scan():    print("start single scan ....")    X = Squares(1, 2)    # 首次会执行__iter__对迭代器进行初始化,    # 并且每次执行将调用__next__将数据返回并保存当前迭代器的状态,直至为不可迭代状态    list1 = [n for n in X]    print(list1)    # 迭代器当前是不可迭代的状态,即list2是空列表    list2 = [n for n in X]       # now list2 is empty    print(list2)    print("end single scan ....")if __name__ == '__main__':    single_scan()>>> python iterator.py

这里写图片描述

迭代器多次扫描

# iterator.pydef mutil_scan():    print("start mutil scan ... ")    # 方式一:每次都是重新创建新的迭代器来进行迭代    list1 = [n for n in Squares(1,2)]    print(list1)    list2 = [n for n in Squares(1, 2)]    print(list2)    # 方式二 转换为列表并用列表解析器来转换    list_iter = list(Squares(1,2))    list3 = [n for n in list_iter]    print(list3)    list4 = [n for n in list_iter]    print(list4)    print("end mutil scan ...")if __name__ == '__main__':    mutil_scan()>>> python iterator.py

这里写图片描述

这里写图片描述

设计可多次迭代的类对象

  • 自定义类可多次迭代
    • 条件:在内置方法中__iter__中返回的迭代器应当新的迭代器对象,而不是self自身对象
# iterator.pyclass MutilIterator:    def __init__(self, wrapper):        self.__wrapper = wrapper    def __iter__(self):        """         每次调用迭代器的时候就创建一个新的迭代器并返回        """        return DefineIterator(self.__wrapper)class DefineIterator:    def __init__(self, wrapped):        self.wrapped = wrapped        self.offset = 0    def __next__(self):        if self.offset >= len(self.wrapped):            raise StopIteration        else:            item = self.wrapped[self.offset]        self.offset += 1        return item#   py2.x 没有next方法,python2.x 和 python3.x 都可用    next = __next__def test_mutil_object_iter():    S = "abcd"    # 索引遍历操作    M = MutilIterator(S)    for x in M:        for y in M:               # 第二次调用迭代器获取新的迭代器对象             print(x+y,end = ",")    print("")if __name__ == '__main__':    test_mutil_object_iter()>>> python iterator.py

这里写图片描述

  • 类的迭代器与生成器混搭
# iterator.pyclass MixIterator:    def __init__(self,start,stop):        self.__start = start        self.__stop = stop    def __iter__(self):        for index in range(self.__start,self.__stop+1):            yield index**2      # 返回一个生成器对象,通过调用next()来显示值def test_mix_iterator():    iterator = MixIterator(1,5)            # 同一个对象可以迭代多次    list1 = [index for index in iterator]      list2 = [index for index in iterator]    print(list1)    print(list2)if __name__ == '__main__':    test_mix_iterator()

这里写图片描述

  • 重构上述设计类的迭代器
# iterator.py# 使用yield生成器可以保class MutilIterator2:    def __init__(self,wrapper):        self.__wrapper = wrapper    def __iter__(self):        print("call iter ... ")        offset = 0        while offset < len(self.__wrapper):            item = self.__wrapper[offset]            offset+=1            yield itemdef test_mutil2_iterator():    S = "abcd"    M = MutilIterator2(S)    for x in M:       # 执行__iter__方法        for y in M:    # 执行__iter__方法,进入方法的时候offset又变为初始化0            print(x+y,end = ",")        print()if __name__ == '__main__':    test_mutil2_iterator()

这里写图片描述

迭代器小结

  • 迭代器是一个很强大的工具,能够让我们创建自定义迭代器对象来完成自己的业务需求,比如支持大型数据库在多个游标中进行数据查询时获取迭代
  • 对象单个迭代器对象,即不能作为类似于上述的操作,python有map、zip、函数生成器以及生成器表达式
  • 对象多个迭代器对象,即可以来操作上述的动作,python有list、string、range
  • 使用类的迭代器,我们可以自定义迭代器是单例还是多例

个人公众号

这里写图片描述

原创粉丝点击