python中序列类型哪三种(自定义序列类型)
python中序列类型哪三种(自定义序列类型)""" 普通的加法会在内存中产生一个新的序列对象 时间 空间开销相对比较大 必须要是类型完全一致才能够使用这种合并方式 """ a b c = [1 2] [3 4] (5 6) d = a b # [1 2] [3 4] print(d) # result: # [1 2 3 4] d = a c # [1 2] (5 6) print(d) # result: # TypeError: can only concatenate list (not "tuple") to list """ = 可以理解为原地加,单纯地在原对象上进行修改,效率比 要高很多 这个功能背后有一个魔法函数,__iadd__(self values) 上一小节中有这个函数具体的实现,我们可以看到,它是调用了 extend()方法 所以本质上,它和调用 exten
序列类型的分类按照序列存储数据的类型
- 容器序列:list tuple deque
- 扁平序列:str bytes array.array bytearray
按照序列是否可变
- 可变序列:list deque array.array bytearray
- 不可变序列:str tuple bytes
引言
- collections.abc模块中有很多内置的抽象基类
- 序列主要和两个抽象基类有关:Sequence 和 MutableSequence
细节
Sequence
""" Sequence 抽象基类 它继承了Sized Iterable Contain 这三个抽象基类 """ class Sequence(Sized Iterable Container): """All the operations on a read-only sequence. Concrete subclasses must override __new__ or __init__ __getitem__ and __len__. """ __slots__ = () @abstractmethod def __getitem__(self index): raise IndexError def __iter__(self): i = 0 try: while True: v = self[i] yield v i = 1 except IndexError: return def __contains__(self value): for v in self: if v == value: return True return False def __reversed__(self): # 该魔法函数使得序列类型可以反转 for i in reversed(range(len(self))): yield self[i]
class Sized(metaclass=ABCMeta): __slots__ = () @abstractmethod def __len__(self): # 这个魔法函数使得序列类型可以使用 len()获得长度 return 0 @classmethod def __subclasshook__(cls C): if cls is Sized: if any("__len__" in B.__dict__ for B in C.__mro__): return True return NotImplemented
class Iterable(metaclass=ABCMeta): __slots__ = () @abstractmethod def __iter__(self): # 这个魔法函数使得序列类型可以进行 for 循环 while False: yield None @classmethod def __subclasshook__(cls C): if cls is Iterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented
class Container(metaclass=ABCMeta): __slots__ = () @abstractmethod def __contains__(self x): # 这个魔法函数使得序列类型可以使用 in 操作符 return False @classmethod def __subclasshook__(cls C): if cls is Container: if any("__contains__" in B.__dict__ for B in C.__mro__): return True return NotImplemented
MutableSequence
class MutableSequence(Sequence): __slots__ = () """All the operations on a read-write sequence. Concrete subclasses must provide __new__ or __init__ __getitem__ __setitem__ __delitem__ __len__ and insert(). """ @abstractmethod def __setitem__(self index value): raise IndexError @abstractmethod def __delitem__(self index): raise IndexError def __iadd__(self values): # 使得序列可以使用 = 运算符号进行计算 self.extend(values) return self # ......只列出几个有代表意义的魔法函数...... # 这些魔法函数使得序列类型可以改变 序列的 、 =和extend
引言
- 对于可变序列,我们有三种方式来扩充原始序列
- 三种方式有原理和效率上的不同,我们要根据实际情况选择合适的方式来使用
使用范例
""" 普通的加法会在内存中产生一个新的序列对象 时间 空间开销相对比较大 必须要是类型完全一致才能够使用这种合并方式 """ a b c = [1 2] [3 4] (5 6) d = a b # [1 2] [3 4] print(d) # result: # [1 2 3 4] d = a c # [1 2] (5 6) print(d) # result: # TypeError: can only concatenate list (not "tuple") to list
""" = 可以理解为原地加,单纯地在原对象上进行修改,效率比 要高很多 这个功能背后有一个魔法函数,__iadd__(self values) 上一小节中有这个函数具体的实现,我们可以看到,它是调用了 extend()方法 所以本质上,它和调用 extend()函数产生的效果是一模一样的 """ a b c = [1 2] [3 4] (5 6) a = b print(a) # result: # [1 2 3 4] a = c print(a) # result: # [1 2 3 4 5 6]
在鸭子类型那一小节,我们分析了extend()函数的参数要求,只要是可迭代类型都能够作为参数扩充列表。
=操作本质上就是调用 extend() 函数,所以能将列表和元组进行合并也就不奇怪了,因为他们本质上都是可迭代的类型。
实现可切片的对象引言
切片介绍
# 使用模式:[start:end:step] """ start: 切片开始的位置,默认是 0 end: 切片截止(不包括)的位置,默认是列表长度 step: 切片的步长,默认是 1 start和end为默认值时可以省略不写,step为默认值时可以连同最后的冒号一起省略 step为负数时,表示反向切片,此时需满足: start > end """
切片举例
li = [8 4 3 2 1 7] li[::] # 返回原序列 li[::-1] # 返回原序列的逆序列表 li[::2] # 隔一个取一个,所有偶数位置 li[1::2] # 隔一个取一个,所有奇数位置 li[3:6] # 取[3 6)区间内的所有元素,左包含,右不包含 li[0:666] # 结束位置大于列表长度,从尾部截断,返回原列表 li[666:] # 开始位置大于列表长度,直接返回空列表 li = [6 6] li[:0] = [1 2] # 列表头部插入元素 [1 2 6 6] li[1:1] = [1 1] # 列表的某一位置插入元素 [6 1 1 6] li[:1] = [1 1] # 替换列表元素 [1 1 6] li[1:] = [1 1] # 替换列表元素 [6 1 1]
使用案例
class group: def __init__(self group_name staffs): self.group_name = group_name self.staffs = staffs def __reversed__(self): # reversed(group) self.staffs.reverse() """ 在使用切片和索引访问操作时,相关的参数会传递到 __getitem__(self item) 中 我们通常希望,切片返回的对象和原对象是同一种类型 使用切片的话,传入的item是一个slice类型 使用索引访问,传入的item是一个int类型 """ def __getitem__(self item): # 对象可切片的关键 cls = type(self) # 获得该实例的类型 if isinstance(item slice): return cls(self.group_name self.staffs[item]) # 委托给列表实现切片 elif isinstance(item int): return self.staffs[item] def __len__(self): return len(self.staffs) def __iter__(self): return iter(self.staffs) # 后面会详细讲解 def __contains__(self item): return item in self.staffs # 同样委托给列表的in操作来实现 def __str__(self): return "name:{name}\nstaffs:{staffs}".format(name=self.group_name staffs=self.staffs) staffs = ["MetaTian0" "MetaTian1" "MetaTian2"] group = Group("HIT" staffs) print(group[1]) # 索引访问 print(group[0:2]) # 切片 reversed(group) # 反转 print(group) print(len(group)) # 长度 print("MetaTian0" in group "MetaTian6" in group) # in 操作符 # resutl: # MetaTian1 # name:HIT; staffs:['MetaTian0' 'MetaTian1'] # name:HIT; staffs:['MetaTian2' 'MetaTian1' 'MetaTian0'] # 3 # True False bisect模块
引言
- 如果我们在一个有序序列中需要增加一个元素,但任然要维持序列的有序性,可以使用append()添加元素,再调用sort()来重新排序。
- bisect模块用来维持已排序序列(升序)的顺序,效率更高。
- 两个关键函数insort()和bisect
使用案例
import bisect int_list = [] """ 在插入过程中维护序列的有序性 """ bisect.insort(int_list 2) bisect.insort(int_list 6) bisect.insort(int_list 1) bisect.insort(int_list 3) bisect.insort(int_list 5) print(int_list) # result: # [1 2 3 5 6] """ 查询一个元素在序列中应该插入的位置 bisect(): 同值元素默认插在右侧 bisect_left(): 同值元素默认插在左侧 """ print(bisect.bisect(int_list 3)) print(bisect.bisect_left(int_list 3)) # result: # 3 # 2 列表一定是最好的吗
引言
- Python中的array,只可以存储指定类型的元素
- 相当与是C语言中的数组,操作效率比列表更高
- 官方文档:https://docs.python.org/3.7/library/array.html?highlight=array
使用案例
import array """ 使用前要引入array模块,要申明存储的对象类型 """ my_array = array.array("i") my_array.append(666) my_array.append(4) my_array.extend([1 2 3]) my_list = my_array.tolist() # 大部分基本的操作函数和序列差不多,这里就不做过多介绍 print(my_array) # result: # array('i' [666 4 1 2 3]) # [666 4 1 2 3] 列表推导、生成器表达式、字典推导
引言
- 推导表达式是一种更加简洁高效,生成相关对象的一种方式
使用案例
""" 列表推导 生成1-20中的奇数 """ # 普通方式 odd_list = [] for i in range(1 21): if i%2 == 1: odd_list.append(i) # 列表推导 odd_list = [i for i in range(1 21) if i%2 == 1] """ 生成器表达式 后面部分会详细介绍其原理 """ odd_list = (i for i in range(1 21) if i%2 == 1) print(type(odd_list)) # result: # <class 'generator'> for item in odd_list: print(item end=' ') # result: # 1 3 5 7 9 11 13 15 17 19 """ 字典推导式 """ my_dict = {"a":1 "b":2 "c":3} reversed_dict = {val:k for k val in my_dict.items()} print(reversed_dict) # result: # {1: 'a' 2: 'b' 3: 'c'}
喜欢python qun:839383765 可以获取Python各类免费最新入门学习资料!