美文网首页
python数据结构(二) 高级数据结构

python数据结构(二) 高级数据结构

作者: nowherespyfly | 来源:发表于2019-11-02 23:54 被阅读0次

关于常见的内置类型可参见我的上一篇文章:python数据结构(一) 内置类型.

1. 扩展内置类型

python内置类型可以通过实例进行扩展。当想要向一个内置容器对象中添加某种功能时,通常来说,我们有两种选择:1)创建一个新对象,并将某个容器作为其属性,即组合的方式,当我们想要用容器存储一些对象并利用它的一些特性时,组合是比较好的选择;2)创建内置对象的子类并添加类方法来实现需要的功能,即继承关系,如果需要修改容器对象实际的运作方式,继承的方式更合适。

1) 查看内置类型的方法

如果想要改写某个内置类型的方法,就需要用到dir()来查看,比如想要查看list自定义的方法:

>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
 '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__',
 '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
 '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__',
 '__setattr__', '__setitem__', '__sizeof__',  '__str__',  '__subclasshook__', 'append',
 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

>>> help(list.__contains__)
Help on wrapper_descriptor:

__contains__(self, key, /)
    Return key in self.

其中,__add__就是‘+’, 这个符号是这一个语法糖。如果我们在我们自己定义的对象中重新实现了__add__方法,那么也可以使用 '+' 来连接。
__contains__的语法糖是'in'。
__setitem__和__getitem__分别实现了利用'[]'修改和获取列表的元素值
__iter__是迭代器,实现了for... in。
__new__是构造新对象的方法,每创建一个新对象的时候,都会首先调用__new__返回一个新对象,然后调用__init__对该对象的变量进行初始化。

这些特殊方法都可以通过help函数来获取它们的使用方法。
当我们在对象的方法中利用三个反引号来包装一部分文本时,help函数就可以输出这部分文本。

2) 案例

python内置的dict是无序的,collections中提供了OrderedDict使得key按照添加顺序排列。下面的例子展示了如何实现一个简单地OrderedDict:

from collections import KeysView, ItemsView, ValuesView
class DictSorted(dict):
    def __new__(*args, **kwargs):
        new_dict = dict.__new__(*args, **kwargs)
        new_dict.ordered_keys = []
        return new_dict
    
    def __setitem__(self, key, value):
        '''self[key] = value syntax'''
        if key not in self.ordered_keys:
            self.ordered_keys.append(key)
        super().__setitem__(key, value)
        
    def setdefault(self, key, value):
        if key not in self.ordered_keys:
            self.ordered_keys.append(key)
        return super().setdefault(key, value)
    
    def keys(self):
        return KeysView(self)
    
    def values(self):
        return ValuesView(self)
    
    def items(self):
        return ItemsView(self)
        
    def __iter__(self):
        '''for x in self syntax'''
        return self.ordered_keys.__iter__()

__new__方法创建一个新的dict,并添加一个空的列表属性。
keys, values, items返回了dict的视图,通过KeysView, ItemsView, ValuesView得到只读的view对象,它们用__iter__方法遍历所有的key,然后用__getitem__来取值,需要定义好__iter__方法来确保它们正常工作。如果不重写这三个方法,就不能返回有序的视图。
__iter__方法确保我们遍历所有的key,按照正确的顺序返回,实现了for ... in。这里返回的是order_keys中的迭代器。

这里我们只是改写了部分方法,无法确保在所有情况下这个类都可以正常使用。要实现这一功能,可以参考collections。

2. 队列

python提供了3种队列数据结构,包括:先进先出队列(FIFO),后进先出队列(LIFO,即栈),优先级队列。最重要的两个方法分别是put()和get(),用于添加元素及获取元素。

1)先进先出队列(FIFO)

每次往队尾添加元素,从队头获取元素。如果队列已满,将block设为False,则会报出异常,否则阻塞直到可以继续添加元素。get方法同理。

>>> from queue import Queue
>>> q = Queue(maxsize=3)
>>> q.get(block=False)
---------------------------------------------------------------------------
Empty                                     Traceback (most recent call last)
<ipython-input-10-6209e13c9d73> in <module>()
----> 1 q.get(block=False)

C:\ProgramData\Anaconda3\lib\queue.py in get(self, block, timeout)
    165             if not block:
    166                 if not self._qsize():
--> 167                     raise Empty
    168             elif timeout is None:
    169                 while not self._qsize():

Empty:

>>> q.put(4)
>>> q.put(5)
>>> q.get()
4
>>> q.get()
5
>>> q.empty()
True
2) 后进先出队列(LIFO)

后进先出队列其实就是栈,由queue.LifoQueue实现,其操作方式与Queue类似,只是进出顺序不一样。如果没有其他要求,只用list其实就可以满足栈的要求了。必须使用LIFO的原因有两个:

  • LifoQueue支持多线程并发
  • LifoQueue强制使用栈接口,不能在中间插入元素。
3) 优先级队列

优先级队列每次返回当前队列中最重要的元素,queue.PriorityQueue, heapq.heap都可以用于实现这一功能。如果队列为空,则get()方法将会阻塞。

一般每次添加的元素为tuple,第一个元素元素代表其优先级,第二个为数据。也可以实现__lt__方法来达到这一目的。

相关文章

网友评论

      本文标题:python数据结构(二) 高级数据结构

      本文链接:https://www.haomeiwen.com/subject/zuyhbctx.html