python 3.x 自定义序列

自定义序列

  • 序列是python中非常重要的协议(python基于协议来编程的)
  • 与容器相关的数据结构,它的抽象基类都是放在collections下的abc模块
  • abc下的_collections_abc的__all__中定义了collections相关的抽象基类
     1 __all__ = ["Awaitable", "Coroutine",
     2 "AsyncIterable", "AsyncIterator", "AsyncGenerator",
     3 "Hashable", "Iterable", "Iterator", "Generator", "Reversible",
     4 "Sized", "Container", "Callable", "Collection",
     5 "Set", "MutableSet",
     6 "Mapping", "MutableMapping",
     7 "MappingView", "KeysView", "ItemsView", "ValuesView",
     8 "Sequence", "MutableSequence",
     9 "ByteString",
    10 ]

     

与序列相关的抽象基类

Sequence(不可变的序列) --> class Sequence(Reversible, Collection):

  • Reversible类源码
     1 class Reversible(Iterable):
     2 
     3     __slots__ = ()
     4 
     5     @abstractmethod
     6     def __reversed__(self):
     7         while False:
     8             yield None
     9 
    10     @classmethod
    11     def __subclasshook__(cls, C):
    12         if cls is Reversible:
    13             return _check_methods(C, "__reversed__", "__iter__")
    14         return NotImplemented
  • Sized源码
     1 class Sized(metaclass=ABCMeta):
     2 
     3     __slots__ = ()
     4 
     5     @abstractmethod
     6     def __len__(self):
     7         return 0
     8 
     9     @classmethod
    10     def __subclasshook__(cls, C):
    11         if cls is Sized:
    12             return _check_methods(C, "__len__")
    13         return NotImplemented
  • Iterable源码
     1 class Iterable(metaclass=ABCMeta):
     2 
     3     __slots__ = ()
     4 
     5     @abstractmethod
     6     def __iter__(self):
     7         while False:
     8             yield None
     9 
    10     @classmethod
    11     def __subclasshook__(cls, C):
    12         if cls is Iterable:
    13             return _check_methods(C, "__iter__")
    14         return NotImplemented
  • Container源码
     1 class Container(metaclass=ABCMeta):
     2 
     3     __slots__ = ()
     4 
     5     @abstractmethod
     6     def __contains__(self, x):
     7         return False
     8 
     9     @classmethod
    10     def __subclasshook__(cls, C):
    11         if cls is Container:
    12             return _check_methods(C, "__contains__")
    13         return NotImplemented
  • Collection源码
    1 class Collection(Sized, Iterable, Container):
    2 
    3     __slots__ = ()
    4 
    5     @classmethod
    6     def __subclasshook__(cls, C):
    7         if cls is Collection:
    8             return _check_methods(C,  "__len__", "__iter__", "__contains__")
    9         return NotImplemented
  • Sequence源码
     1 class Sequence(Reversible, Collection):
     2 
     3     """All the operations on a read-only sequence.
     4 
     5     Concrete subclasses must override __new__ or __init__,
     6     __getitem__, and __len__.
     7     """
     8 
     9     __slots__ = ()
    10 
    11     @abstractmethod
    12     def __getitem__(self, index):
    13         raise IndexError
    14 
    15     def __iter__(self):
    16         i = 0
    17         try:
    18             while True:
    19                 v = self[i]
    20                 yield v
    21                 i += 1
    22         except IndexError:
    23             return
    24 
    25     def __contains__(self, value):
    26         for v in self:
    27             if v is value or v == value:
    28                 return True
    29         return False
    30 
    31     def __reversed__(self):
    32         for i in reversed(range(len(self))):
    33             yield self[i]
    34 
    35     def index(self, value, start=0, stop=None):
    36         '''S.index(value, [start, [stop]]) -> integer -- return first index of value.
    37            Raises ValueError if the value is not present.
    38         '''
    39         if start is not None and start < 0:
    40             start = max(len(self) + start, 0)
    41         if stop is not None and stop < 0:
    42             stop += len(self)
    43 
    44         i = start
    45         while stop is None or i < stop:
    46             try:
    47                 v = self[i]
    48                 if v is value or v == value:
    49                     return i
    50             except IndexError:
    51                 break
    52             i += 1
    53         raise ValueError
    54 
    55     def count(self, value):
    56         'S.count(value) -> integer -- return number of occurrences of value'
    57         return sum(1 for v in self if v is value or v == value)
    58 
    59 Sequence.register(tuple)
    60 Sequence.register(str)
    61 Sequence.register(range)
    62 Sequence.register(memoryview)

通过以上的源码

  • Sequence继承两个类Reversible, Collection
    • Reversible: 中定义抽象魔法函数@abstractmethod >> def __reversed__(self): >> while False: >> yield None, 数据的反转 如: abc --> cba  
    • Collection: 继承三个类 --> class Collection(Sized, Iterable, Container):  
      • Sized( class Sized(metaclass=ABCMeta): )中定义了抽象魔法函数@abstractmethod >> def __len__(self): >> return 0,这样可以计算Collection的长度.    
      • Iterable( class Iterable(metaclass=ABCMeta): )中定义了抽象魔法函数@abstractmethod >> def __iter__(self): >> while False: >> yield None,这样可以对Collection进行迭代(for循环)    
      • Container( class Container(metaclass=ABCMeta): )中定义了抽象魔法函数@abstractmethod >> def __contains__(self, x): >> return False    
        有了__contains__()方法,可以使用if...in...来做判断,(比如说判断一个数据是否在list里面)
        如果没有__contains__()魔法函数,但是定义了__getitem__()魔法函数,实际上也可以使用if...in..来进行判断.
  • if...in...对python解释器来说,python解释器首选的就是Container中的__contains__()魔法函数,如果没有的话,退一步,去找__getitem__()魔法函数,然后通过__getitem__()魔法函数遍历整个序列(python在内部做了很多的优化)
  • 通过查看Sequence的源码可以知道对于不可变序列类型来说,
    • 继承Reversible实现抽象魔法函数__reversed__()  
    • 继承Collection.实现抽象魔法函数__contains__()和__iter__(),而抽象魔法函数__len__()需要Sequence的子类来实现  
    • Sequence中的抽象魔法函数__getitem__()需要子类来实现,以及构造函数__init__().  

 

MutableSequence(可变的序列) --> class MutableSequence(Sequence):

  • MutableSequence源码
     1 class MutableSequence(Sequence):
     2 
     3     __slots__ = ()
     4 
     5     """All the operations on a read-write sequence.
     6 
     7     Concrete subclasses must provide __new__ or __init__,
     8     __getitem__, __setitem__, __delitem__, __len__, and insert().
     9 
    10     """
    11 
    12     @abstractmethod
    13     def __setitem__(self, index, value):
    14         raise IndexError
    15 
    16     @abstractmethod
    17     def __delitem__(self, index):
    18         raise IndexError
    19 
    20     @abstractmethod
    21     def insert(self, index, value):
    22         'S.insert(index, value) -- insert value before index'
    23         raise IndexError
    24 
    25     def append(self, value):
    26         'S.append(value) -- append value to the end of the sequence'
    27         self.insert(len(self), value)
    28 
    29     def clear(self):
    30         'S.clear() -> None -- remove all items from S'
    31         try:
    32             while True:
    33                 self.pop()
    34         except IndexError:
    35             pass
    36 
    37     def reverse(self):
    38         'S.reverse() -- reverse *IN PLACE*'
    39         n = len(self)
    40         for i in range(n//2):
    41             self[i], self[n-i-1] = self[n-i-1], self[i]
    42 
    43     def extend(self, values):
    44         'S.extend(iterable) -- extend sequence by appending elements from the iterable'
    45         for v in values:
    46             self.append(v)
    47 
    48     def pop(self, index=-1):
    49         '''S.pop([index]) -> item -- remove and return item at index (default last).
    50            Raise IndexError if list is empty or index is out of range.
    51         '''
    52         v = self[index]
    53         del self[index]
    54         return v
    55 
    56     def remove(self, value):
    57         '''S.remove(value) -- remove first occurrence of value.
    58            Raise ValueError if the value is not present.
    59         '''
    60         del self[self.index(value)]
    61 
    62     def __iadd__(self, values):
    63         self.extend(values)
    64         return self
    65 
    66 MutableSequence.register(list)
    67 MutableSequence.register(bytearray)  # Multiply inheriting, see ByteString

通过MutableSequence源码

  • MutableSequence继承Sequence,所以MutableSequence的子类必须覆写Sequence类没有实现的抽象魔法函数__len__()和__getitem__().
  • 以及MutableSequence类中的抽象魔法函数__setitem__()和__delitem__().以及抽象方法insert().以及构造函数__init__()

 

序列的+,+=和extend的区别

  • + 运算符将两个列表合并且生成一个新的对象列表,新列表与原来合并的子列表互不影响.
  • += 运算符内部实现了一个魔法函数__iadd__(self).
     1 def __iadd__(self, values):
     2     self.extend(values)
     3     return self
     4 
     5 # --------------------------------------------------------------------------------------
     6 
     7 def extend(self, values):
     8     'S.extend(iterable) -- extend sequence by appending elements from the iterable'
     9     for v in values:
    10         self.append(v)
    11 
    12 # --------------------------------------------------------------------------------------
    13 
    14 def append(self, value):
    15     'S.append(value) -- append value to the end of the sequence'
    16     self.insert(len(self), value)
    17 
    18 # --------------------------------------------------------------------------------------
    19 
    20 @abstractmethod
    21 def insert(self, index, value):
    22     'S.insert(index, value) -- insert value before index'
    23     raise IndexError

    通过源码:
      += 运算符内部实现了一个魔法函数__iadd__(self).而__iadd__()魔法函数中调用extend()方法,extend()方法将传递进来的可迭代的数据,进行for循环遍历,
           使用append(len(self),value)方法将可迭代的数据元素逐一添加到原有序列的后面append()函数内部调用insert()方法,insert()的意思是将插入的元素,放到指定索引值处 

 1 # 初始化list的两种方式
 2 a = [1, 2]
 3 # 空列表
 4 b = list([9, 8])
 5 
 6 # 将两个列表相加并产生一个新的对象c,新列表与原来的子列表互不影响
 7 c = a + [3, 4]
 8 
 9 # 结果: [1, 2, 3, 4]
10 print(c)
11 
12 # 报错: TypeError: can only concatenate list (not "tuple") to list
13 # 只能将list和list数据类型想合并.
14 # d = a + (11, 22)
15 
16 # ------------------------------------------------------------------------
17 
18 # += 运算符实现两列表合并是在原有的列表上添加一个列表的所有元素
19 a += [5, 6]
20 # 结果: [1, 2, 5, 6]
21 print(a)
22 
23 a += (11, 22)
24 # 结果: [1, 2, 5, 6, 11, 22]
25 print(a)
26 
27 # ------------------------------------------------------------------------
28 
29 # extend() 与 append()区别
30 # extend()将传递进来的序列对象,进行for循环遍历,将元素逐一添加的原有列表中
31 # append()将传递进来的数据当成一个元素,添加到原有列表的末端
32 b.extend([1, 2, 3])
33 c.append([1, 2, 3])
34 
35 # b = [9,8]
36 # 结果: [9, 8, 1, 2, 3]
37 print(b)
38 
39 # c = [1,2,3,4]
40 # 结果: [1, 2, 3, 4, [1, 2, 3]]
41 print(c)

 

实现可切片的对象

模式[start:end:step]

  • start: 表示切片的开始位置,默认为0
  • end : 表示切片截止(但不包含)位置,默认为列表的长度
  • step : 表示切片的步长,默认为1

 

  • 当start为0时可省略
  • 当end为列表长度时可省略
  • 当step为1时可省略,并且省略步长时可以同时省略最后一个冒号.

 

  • 注意: 当step为负整数时,表示反向切片,这时start值要比end值大才行.
  • 所有切片取值的操作会返回一个新的列表

通过示例代码来体会切片的强大之处

  • a_list = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
  • 列表取值的操作
    • a_list[::]                                               返回包含原列表中所有元素的新列表  
    • a_list[::-1]                                            返回包含原列表中所有元素的逆序列表  
    • a_list[::2]                                             隔一个取一个,获取偶数位置的元素  
    • a_list[1::2]                                           隔一个取一个,获取奇数位置的元素  
    • a_list[3:6]                                            指定切片的开始和结束的位置  
    • a_list[0:100]                                        切片结束位置大于列表长度时,从列表尾部截断  
    • a_list[100:]                                          切片开始位置大于列表长度时,返回空列表  
  • 列表修改(赋值)操作
    • a_list[len(a_list):] = [9]                         在列表尾部增加元素  
    • a_list[:0] = [1, 2]                                        在列表头部插入元素  
    • a_list[3:3] = [88]                                        在列表中间指定位置插入元素  
    • a_list[:3] = [1, 2]                                        替换列表元素,等号两边的列表长度相等  
    • a_list[3:] = [4, 5, 6]                                    等号两边的列表长度也可以不相等  
    • a_list[::2] = [0] * 5                                      隔一个修改一个  
    • a_list[::2] = ['a', 'b', 'c', 'd', 'e']                     隔一个修改一个  
    • a_list[::2] = [1, 2, 3]                                   左侧切片不连续,等号两边列表长度必须相等,不然会报错 : 
                                                                       ValueError: attempt to assign sequence of size 3 to extended slice of size 5
                                                                       (尝试将大小为3的序列分配给大小为5的扩展切片)  
    • a_list[:3] = []                                              删除列表中前3个元素  
    • del a_list[:3]                                              切片元素连续  
    • del a_list[::2]                                             切片元素不连续,隔一个删一个  
 1 a_list = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
 2 
 3 # ------------------------------------------------------
 4 # 列表取值的操作
 5 
 6 # 返回包含原列表中所有元素的新列表
 7 # 结果: [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
 8 print(a_list[::])
 9 
10 # 返回包含原列表中所有元素的逆序列表
11 # 结果: [17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
12 print(a_list[::-1])
13 
14 # 隔一个取一个,获取偶数位置的元素
15 # 结果: [3, 5, 7, 11, 15]
16 print(a_list[::2])
17 
18 # 隔一个取一个,获取奇数位置的元素
19 # 结果: [4, 6, 9, 13, 17]
20 print(a_list[1::2])
21 
22 # 指定切片的开始和结束的位置
23 # 结果: [6, 7, 9]
24 print(a_list[3:6])
25 
26 # 切片结束位置大于列表长度时,从列表尾部截断
27 # 结果: [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
28 print(a_list[0:100])
29 
30 # 切片开始位置大于列表长度时,返回空列表
31 # 结果: []
32 print(a_list[100:])
33 
34 # ------------------------------------------------------
35 # 列表修改(赋值)操作
36 
37 # 在列表尾部增加元素
38 a_list[len(a_list):] = [9]
39 # 结果: [3, 4, 5, 6, 7, 9, 11, 13, 15, 17, 9]
40 print(a_list)
41 
42 # 在列表头部插入元素
43 a_list[:0] = [1, 2]
44 # 结果: [1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
45 print(a_list)
46 
47 # 在列表中间指定位置插入元素
48 a_list[3:3] = [88]
49 # 结果: [3, 4, 5, 88, 6, 7, 9, 11, 13, 15, 17]
50 print(a_list)
51 
52 # 替换列表元素,等号两边的列表长度相等
53 a_list[:3] = [1, 2]
54 # 结果: [1, 2, 6, 7, 9, 11, 13, 15, 17]
55 print(a_list)
56 
57 # 等号两边的列表长度也可以不相等
58 a_list[3:] = [4, 5, 6]
59 # 结果: [3, 4, 5, 4, 5, 6]
60 print(a_list)
61 
62 # 隔一个修改一个
63 a_list[::2] = [0] * 5
64 # 结果: [0, 4, 0, 6, 0, 9, 0, 13, 0, 17]
65 print(a_list)
66 
67 # 隔一个修改一个
68 a_list[::2] = ['a', 'b', 'c', 'd', 'e']
69 # 结果: ['a', 4, 'b', 6, 'c', 9, 'd', 13, 'e', 17]
70 print(a_list)
71 
72 # 左侧切片不连续,等号两边列表长度必须相等
73 # 不然会报错 : ValueError: attempt to assign sequence of size 3 to extended slice of size 5
74 # 尝试将大小为3的序列分配给大小为5的扩展切片
75 a_list[::2] = [1, 2, 3]
76 
77 # 删除列表中前3个元素
78 a_list[:3] = []
79 # 结果: [6, 7, 9, 11, 13, 15, 17]
80 print(a_list)
81 
82 # 切片元素连续
83 del a_list[:3]
84 # 结果: [6, 7, 9, 11, 13, 15, 17]
85 print(a_list)
86 
87 # 切片元素不连续,隔一个删一个
88 del a_list[::2]
89 # 结果: [4, 6, 9, 13, 17]
90 print(a_list)

 

自定义切片对象

  • 魔法函数def __getitem__(self, item)是实现切片的关键.
  • 如果一个对象没有实现魔法函数def __getitem__(self, item),对其执行切片的操作,会报错TypeError: 'Group' object is not subscriptable("Group"对象没有下标)
 1 """
 2     自定义切片对象
 3 
 4     组的概念(生活中常见的概念)
 5         比如学校里的学习小组,公司里的开发组,Django里的用户分组(Django里的Group是管理用户的user)
 6 
 7     需求: 定义一个类Group,希望Group支持切片操作,Group类是不可修改的序列
 8 """
 9 
10 
11 class Group:
12     """
13         自定义不可变序列,需要实现的魔法函数
14             __reversed__()
15             __getitem__()
16             __len__()
17             __iter__()
18             __contains__()
19     """
20 
21     def __init__(self, group_name, company_name, staffs):
22         self.group_name = group_name
23         self.company_name = company_name
24         self.staffs = staffs
25 
26     def __reversed__(self):
27         pass
28 
29     def __getitem__(self, item):
30         """
31             对Group做切片操作,将切片的参数传递给__getitem__()方法中
32             但是有一个问题存在,python的list进行切片操作后还是list对象.
33             而此时对Group做切片操作返回的不是Group对象,而是list.
34 
35             所以希望Group进行切片操作后还是一个Group对象,这样的话,就可以不停的对Group对象进行切片操作.
36         """
37         # sub_group = group[:2] --> group[:2:] --> group[None:2:None]
38         # item = {slice}slice(None, 2, None)
39         return self.staffs[item]
40 
41     def __len__(self):
42         pass
43 
44     def __iter__(self):
45         pass
46 
47     def __contains__(self, item):
48         pass
49 
50 
51 lang_staffs = ["python", "java", "php", "android"]
52 group = Group("computer", "language", lang_staffs)
53 
54 # debug : sub_group = {list}<class 'list'>: ['python', 'java']
55 sub_group = group[:2]
56 
57 # 结果: ['python', 'java'] 对Group对象进行切片操作,返回的结果类型不是Group而是list,这不是我们希望得到的数据类型.
58 print(sub_group)

 

 1 """
 2     自定义切片对象
 3     需求: 定义一个类Group,希望Group支持切片操作,Group类是不可修改的序列
 4           Group进行进行切片操作后,获取的结果类型还是一个Group类型
 5 """
 6 import numbers
 7 
 8 
 9 class Group:
10     """
11         自定义不可变序列,需要实现的魔法函数
12             __reversed__()
13             __getitem__()
14             __len__()
15             __iter__()
16             __contains__()
17     """
18 
19     def __init__(self, group_name, company_name, staffs):
20         self.group_name = group_name
21         self.company_name = company_name
22         self.staffs = staffs
23 
24     def __reversed__(self):
25         pass
26 
27     def __getitem__(self, item):
28         """
29             希望Group进行切片操作后还是一个Group对象,这样的话,就可以不停的对Group对象进行切片操作.
30 
31             当进行切片操作的时候,python解释器会将切片初始化一个slice对象,然后将slice对象传递给__getitem__()
32             魔法函数的item.
33 
34             当给序列对象指定索引操作(group[0])时,__getitem__()魔法函数的item将接收一个int类型的值.
35         """
36         # 获取当前self的class
37         cls = type(self)
38         if isinstance(item, slice):
39             return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
40 
41         elif isinstance(item, numbers.Integral):
42 
43             # self.staffs[item] --> 得到的结果是一个数字 --> 将其变成一个数组[self.staffs[item]]
44             # 因为Group只接收数组,才能不断的做切片操作
45             return cls(group_name=self.group_name, company_name=self.company_name, staffs=[self.staffs[item]])
46 
47     def __len__(self):
48         pass
49 
50     def __iter__(self):
51         pass
52 
53     def __contains__(self, item):
54         pass
55 
56 
57 lang_staffs = ["python", "java", "php", "android"]
58 group = Group("computer", "language", lang_staffs)
59 
60 # debug:
61 #       sub_group = {Group} <__main__.Group object at 0x0000000003657C18>
62 #       company_name = {str} 'language'
63 #       group_name = {str} 'computer'
64 #       staffs = {list} <class 'list'>: ['python', 'java']
65 sub_group = group[:2]
66 
67 # debug:
68 #       sub_group1 = {Group} <__main__.Group object at 0x00000000024102B0>
69 #       company_name = {str} 'language'
70 #       group_name = {str} 'computer'
71 #       staffs = {list} <class 'list'>: ['python']
72 sub_group1 = group[0]

 

 1 """
 2     自定义序列对象
 3     需求: 定义一个类Group,Group支持切片操作,Group类是不可修改的序列
 4 """
 5 import numbers
 6 
 7 
 8 class Group:
 9     """
10         自定义不可变序列,需要实现的魔法函数
11             __reversed__()
12             __getitem__()
13             __len__()
14             __iter__()
15             __contains__()
16     """
17 
18     def __init__(self, group_name, company_name, staffs):
19         self.group_name = group_name
20         self.company_name = company_name
21         self.staffs = staffs
22 
23     def __reversed__(self):
24         self.staffs.reverse()
25 
26     def __getitem__(self, item):
27         cls = type(self)
28         if isinstance(item, slice):
29             return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
30         elif isinstance(item, numbers.Integral):
31             return cls(group_name=self.group_name, company_name=self.company_name, staffs=[self.staffs[item]])
32 
33     def __len__(self):
34         # Group的长度委托数组来完成
35         return len(self.staffs)
36 
37     def __iter__(self):
38         # 先这样写,后面文章会详细说明
39         return iter(self.staffs)
40 
41     def __contains__(self, item):
42         # if...in...
43         if item in self.staffs:
44             return True
45         else:
46             return False
47 
48 
49 lang_staffs = ["python", "java", "php", "android"]
50 group = Group("computer", "language", lang_staffs)
51 
52 
53 def do_reversed():
54     """ 测试反转顺序 """
55     reversed(group)
56     do_iter()
57 
58 
59 def do_len():
60     """ 测试__len__() """
61     print(len(group))
62 
63 
64 def do_contains():
65     """ 测试__contains__() """
66     if "python" in group:
67         print("YES")
68     else:
69         print("NO")
70 
71 
72 def do_iter():
73     """ 测试__iter__() """
74     for item in group:
75         print(item)
76 
77 
78 # 结果: 4
79 do_len()
80 
81 # 结果:
82 #       python
83 #       java
84 #       php
85 #       android
86 do_iter()
87 
88 # 结果: YES
89 do_contains()
90 
91 # 结果:
92 #       android
93 #       php
94 #       java
95 #       python
96 do_reversed()

 

bisect模块

  • 作用 :
    • python中处理已排序的序列的查找模块,用来维护已排序的序列(可修改的序列)  
    • 排序的顺序是升序  
    • 始终维护一个已排序的序列  
  • bisect中的方法都是通过二分查找算法实现的.
  • insort()与insort_right()是同一个方法
    • 将一个数据插入到以排序的序列中,对序列进行修改.如果插入的数据在序列中已存在,那么插入到已存在数据的最右端  
    • 如: [1, 2, 2, 3]插入数据2(new) --> [1, 2, 2, 2(new), 3]  
  • insort_left()  
    • 将一个数据插入到以排序的序列中,对序列进行修改.如果插入的数据在序列中已存在,那么插入到已存在数据的最左端  
    • 如: [1, 2, 2, 3]插入数据2(new) --> [1, 2(new), 2, 2, 3]  
  • bisect()与bisect_right()是同一个方法
    • 返回要插入的数据在已排序序列中要插入的索引值,未对序列进行修改.  
    • 如果插入的数据在序列中已存在,那么将返回插入到已存在数据的最右端的索引值  
    • 如: [1, 2, 2, 3]插入数据2(new) --> 返回要插入的索引值是3  
  • bisect_left()
    • 返回要插入的数据在已排序序列中要插入的索引值,未对序列进行修改.  
    • 如果插入的数据在序列中已存在,那么将返回插入到已存在数据的最左端的索引值  
    • 如: [1, 2, 2, 3]插入数据2(new) --> 返回要插入的索引值是1  
 1 import bisect
 2 
 3 inter_list = []
 4 bisect.insort(inter_list, 3)
 5 bisect.insort(inter_list, 2)
 6 bisect.insort(inter_list, 6)
 7 bisect.insort(inter_list, 1)
 8 bisect.insort(inter_list, 5)
 9 bisect.insort(inter_list, 4)
10 
11 # 结果: [1, 2, 3, 4, 5, 6]
12 print(inter_list)

 

 1 import bisect
 2 
 3 inter_list = []
 4 bisect.insort(inter_list, 3)
 5 bisect.insort(inter_list, 2)
 6 bisect.insort(inter_list, 6)
 7 bisect.insort(inter_list, 1)
 8 bisect.insort(inter_list, 5)
 9 bisect.insort(inter_list, 4)
10 
11 # 结果: 插入到索引值为2的位置上
12 print(bisect.bisect_left(inter_list, 3))
13 
14 # 结果: 插入到索引值为3的位置上
15 print(bisect.bisect(inter_list, 3))
16 
17 # 结果: [1, 2, 3, 4, 5, 6]
18 # 通过结果证明执行bisect_left()和bisect()这两方法,只是返回需要插入的数据应插入到已排序序列的索引值,
19 # 并没有对已排序的序列进行修改.
20 print(inter_list)

 

 1 import bisect
 2 from collections import deque
 3 
 4 inter_list = deque()
 5 bisect.insort(inter_list, 'python')
 6 bisect.insort(inter_list, 'java')
 7 bisect.insort(inter_list, 'php')
 8 bisect.insort(inter_list, 'android')
 9 bisect.insort(inter_list, 'ios')
10 bisect.insort(inter_list, 'c++')
11 
12 # 4
13 print(bisect.bisect_left(inter_list, 'php'))
14 bisect.insort_left(inter_list, 'php')
15 
16 # 结果: deque(['android', 'c++', 'ios', 'java', 'php', 'php', 'python'])
17 print(inter_list)

 

array(数组)模块

  • 数组是连续的内存空间,它的性能非常的高
  • 在做数据处理或者算法,用array特别多,因为array的效率和性能比list高很多.
  • array只能存放指定的数据类型
  • append() ----------- append a new item to the end of the array
  • buffer_info() ------ return information giving the current memory info
  • byteswap() --------- byteswap all the items of the array
  • count() ------------ return number of occurrences of an object
  • extend() ----------- extend array by appending multiple elements from an iterable
  • fromfile() --------- read items from a file object
  • fromlist() --------- append items from the list
  • frombytes() -------- append items from the string
  • index() ------------ return index of first occurrence of an object
  • insert() ----------- insert a new item into the array at a provided position
  • pop() -------------- remove and return item (default last)
  • remove() ----------- remove first occurrence of an object
  • reverse() ---------- reverse the order of the items in the array
  • tofile() ----------- write all items to a file object
  • tolist() ----------- return the array converted to an ordinary list
  • tobytes() ---------- return the array converted to a string
 1 import array
 2 
 3 a_list = [11, 22, 33]
 4 b_list = [44, 55, 66]
 5 
 6 my_array = array.array("i")
 7 
 8 my_array.append(1)
 9 my_array.append(2)
10 my_array.append(4)
11 my_array.append(6)
12 my_array.append(3)
13 my_array.append(6)
14 
15 # 结果: array('i', [1, 2, 4, 6, 3, 6])
16 print(my_array)
17 
18 # 结果: (34258736, 6)
19 print(my_array.buffer_info())
20 
21 # 结果: 6在数组中出现的次数 2
22 print(my_array.count(6))
23 
24 # 将序列中的元素逐一添加到数组的后面
25 my_array.extend(a_list)
26 # 结果: array('i', [1, 2, 4, 6, 3, 6, 11, 22, 33])
27 print(my_array)
28 
29 # 将列表中的元素逐一添加到数组的后面
30 my_array.fromlist(b_list)
31 # 结果: array('i', [1, 2, 4, 6, 3, 6, 11, 22, 33, 44, 55, 66])
32 print(my_array)
33 
34 # 将字节转换成机器码
35 my_array.frombytes(bytes(4))
36 # 结果: array('i', [1, 2, 4, 6, 3, 6, 11, 22, 33, 44, 55, 66, 0])
37 print(my_array)
38 
39 # 报错: ValueError: bytes length not a multiple of item size
40 # 字节长度不是项大小的倍数
41 # my_array.frombytes(bytes(3))
42 
43 # 将第一个匹配的元素的索引值返回
44 index1 = my_array.index(6)
45 # 结果: 3
46 print(index1)
47 
48 # 将元素77添加到指定索引的位置上. insert(索引值,元素)
49 my_array.insert(0, 77)
50 # 结果: array('i', [77, 1, 2, 4, 6, 3, 6, 11, 22, 33, 44, 55, 66, 0])
51 print(my_array)
52 
53 # pop()方法默认移除最后一个元素,并将移除的元素返回
54 pop_a = my_array.pop()
55 # 结果: 0
56 print(pop_a)
57 # 结果: array('i', [77, 1, 2, 4, 6, 3, 6, 11, 22, 33, 44, 55, 66])
58 print(my_array)
59 
60 # pop()可以指定要移除元素的索引值,并将移除的元素返回
61 pop_b = my_array.pop(3)
62 # 结果: 4
63 print(pop_b)
64 # 结果: array('i', [77, 1, 2, 6, 3, 6, 11, 22, 33, 44, 55, 66])
65 print(my_array)
66 
67 # remove() 删除第一次匹配的元素,不返回删除的元素.
68 # 如果删除的元素不存在,报错ValueError: array.remove(x): x not in list
69 array_remove = my_array.remove(6)
70 # 结果: None
71 print(array_remove)
72 # 结果: array('i', [77, 1, 2, 3, 6, 11, 22, 33, 44, 55, 66])
73 print(my_array)
74 
75 # 将数组倒序
76 my_array.reverse()
77 # 结果: array('i', [66, 55, 44, 33, 22, 11, 6, 3, 2, 1, 77])
78 print(my_array)
79 
80 # 将数组转化成列表
81 tolist = my_array.tolist()
82 # 结果: [66, 55, 44, 33, 22, 11, 6, 3, 2, 1, 77]
83 print(tolist)

 

列表推导式,字典推导式,生成器

 1 """
 2     列表推导式(列表生成式)
 3         通过一行代码来生成列表
 4 
 5     range(n)从零开始,到n-1截止
 6 
 7     列表推导式的出现,可以取代map,reduce,filter函数式编程
 8 """
 9 
10 # 需求: 提取1~20之间的奇数
11 a_list = [x for x in range(21) if x % 2 == 1]
12 # 结果: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
13 print(a_list)
14 
15 # --------------------------------------------------------------------------------
16 
17 # 使用filter + map 函数式编程,需要两行代码.
18 filter_pattern = filter(lambda x: True if x % 2 == 1 else False, range(21))
19 map_obj = map(lambda x: x, list(filter_pattern))
20 # 结果: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
21 print(list(map_obj))

 

 

 1 """
 2     字典推导式(字典生成式)
 3         通过一行代码来生成字典
 4 """
 5 
 6 # 需求: 将字典的key,value颠倒
 7 my_dict = {"python": 22, "java": 24, "php": 8}
 8 
 9 result_dict = {value: key for key, value in my_dict.items()}
10 # {22: 'python', 24: 'java', 8: 'php'}
11 print(result_dict)
12 
13 
14 
15 # 需求将字典的key放到set()集合中
16 key_set = {key for key in my_dict}
17 # 结果: <class 'set'>
18 print(type(key_set))
19 # 结果: {'php', 'python', 'java'}
20 print(key_set)
21 
22 
23 
24 # 第二种方法,使用字典的内置方法
25 key_set1 = set(my_dict.keys())
26 # 结果: <class 'set'>
27 print(type(key_set1))
28 # {'python', 'php', 'java'}
29 print(key_set1)

 

 

 1 """
 2     推导式变成生成器
 3 """
 4 
 5 # 需求: 从0~20中取出所有的可以被5整除的元素的生成器
 6 my_gen = (x for x in range(21) if x % 5 == 0)
 7 # 结果: <class 'generator'>
 8 print(type(my_gen))
 9 # 结果: [0, 5, 10, 15, 20]
10 print(list(my_gen))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

********

posted on 2019-04-06 12:00  jaydenjune  阅读(137)  评论(0)    收藏  举报

导航