1、序列类型的分类
- 容器序列:list、tuple、deque
- 扁平序列:str、bytes、bytearray、array.array
- 可变序列:list、deque、bytearray、array、dict、set
- 不可变序列:str、tuple、bytes
- 有序序列:list、str、tuple
- 无序序列:dict、set
2、python中序列类型的abc继承关系
from collections import abc
查看abc模块
from _collections_abc import *
from _collections_abc import __all__
选择_collections_abc
,里面定义了非常多的抽象基类,其中序列相关的是Sequence
(不可变序列)、MutableSequence
(可变序列)
_collections_abc
部分源码如下:
from abc import ABCMeta, abstractmethod
import sys
__all__ = ["Awaitable", "Coroutine",
"AsyncIterable", "AsyncIterator", "AsyncGenerator",
"Hashable", "Iterable", "Iterator", "Generator", "Reversible",
"Sized", "Container", "Callable", "Collection",
"Set", "MutableSet",
"Mapping", "MutableMapping",
"MappingView", "KeysView", "ItemsView", "ValuesView",
"Sequence", "MutableSequence",
"ByteString",
]
Sequence
源码如下:
class Sequence(Reversible, Collection):
"""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 is value or v == value:
return True
return False
def __reversed__(self):
for i in reversed(range(len(self))):
yield self[i]
def index(self, value, start=0, stop=None):
'''S.index(value, [start, [stop]]) -> integer -- return first index of value.
Raises ValueError if the value is not present.
Supporting start and stop arguments is optional, but
recommended.
'''
if start is not None and start < 0:
start = max(len(self) + start, 0)
if stop is not None and stop < 0:
stop += len(self)
i = start
while stop is None or i < stop:
try:
v = self[i]
if v is value or v == value:
return i
except IndexError:
break
i += 1
raise ValueError
def count(self, value):
'S.count(value) -> integer -- return number of occurrences of value'
return sum(1 for v in self if v is value or v == value)
Sequence.register(tuple)
Sequence.register(str)
Sequence.register(range)
Sequence.register(memoryview)
Sequence
又继承了Reversible
和Collection
两个类
Reversible
源码如下:
class Reversible(Iterable):
__slots__ = ()
@abstractmethod
def __reversed__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is Reversible:
return _check_methods(C, "__reversed__", "__iter__")
return NotImplemented
Collection
源码如下:
class Collection(Sized, Iterable, Container):
__slots__ = ()
@classmethod
def __subclasshook__(cls, C):
if cls is Collection:
return _check_methods(C, "__len__", "__iter__", "__contains__")
return NotImplemented
Collection
又继承了Sized
、Iterable
、Container
三个类
Sized
源码如下:
class Sized(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __len__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Sized:
return _check_methods(C, "__len__")
return NotImplemented
可以看出Sized
实现了__len__()
抽象方法,所以序列重要使用len()
内置函数就可以调用__len__()
,计算出序列的长度
Iterable
源码如下:
class Iterable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is Iterable:
return _check_methods(C, "__iter__")
return NotImplemented
可以看出Iterable
实现了__iter__
抽象方法,就是一个可迭代对象,可以使用for循环进行遍历
Container
源码如下:
class Container(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __contains__(self, x):
return False
@classmethod
def __subclasshook__(cls, C):
if cls is Container:
return _check_methods(C, "__contains__")
return NotImplemented
可以看出Container
实现了__contains__
抽象方法,就可以使用if xxx in xxx进行判断数据是否存在;但__gititem__
也可以进行判断
MutableSequence
继承自Sequence
完整代码如下:
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
@abstractmethod
def insert(self, index, value):
'S.insert(index, value) -- insert value before index'
raise IndexError
def append(self, value):
'S.append(value) -- append value to the end of the sequence'
self.insert(len(self), value)
def clear(self):
'S.clear() -> None -- remove all items from S'
try:
while True:
self.pop()
except IndexError:
pass
def reverse(self):
'S.reverse() -- reverse *IN PLACE*'
n = len(self)
for i in range(n//2):
self[i], self[n-i-1] = self[n-i-1], self[i]
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
for v in values:
self.append(v)
def pop(self, index=-1):
'''S.pop([index]) -> item -- remove and return item at index (default last).
Raise IndexError if list is empty or index is out of range.
'''
v = self[index]
del self[index]
return v
def remove(self, value):
'''S.remove(value) -- remove first occurrence of value.
Raise ValueError if the value is not present.
'''
del self[self.index(value)]
def __iadd__(self, values):
self.extend(values)
return self
MutableSequence.register(list)
MutableSequence.register(bytearray) # Multiply inheriting, see ByteString
3、序列的+、+=、append()和extend()的区别
3.1、+
只能操作两个类型一致的对象,比如两个列表相加;如果两个类型不一致的对象相加,就会报TypeError
异常
# "+"两边是相同的类型
a = [1, 2]
b = a + [3, 4]
print(b)
a = [1, 2]
b = a + (3, 4)
print(b)
3.2、+=
就地加,内部是通过MutableSequence
源码里的__iadd__()
魔法函数实现
def __iadd__(self, values):
self.extend(values)
return self
而__iadd__
()内部调用了extend()
方法,extend()
方法可加一个可迭代对象,而extend()
方法中存在 for...in...
来迭代可迭代对象,将迭代出的元素放进append()
中
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
for v in values:
self.append(v)
所以+=
后可加一个可迭代对象
# "+="就地加,可以加不同的序列类型,实际上是使用了extend方法
a = [1, 2]
a += [3, 4]
print(a)
b = [1, 2]
b += (3, 4)
print(b)
3.3、extend()
没有返回值,后可加一个可迭代对象
# extend()后可以加可迭代的对象,实际上是循环调用append方法
a = [1, 2]
a.extend(range(3, 6))
print(a)
# extend()没有返回值
a = a.extend(range(3, 6))
print(a)
3.4、append()
是直接将参数当作一个元素添加进入了,参数既可以是单个元素,也可以是一个可迭代对象;也没有返回值
def append(self, value):
'S.append(value) -- append value to the end of the sequence'
self.insert(len(self), value)
# "append"后是直接加的value值
a = [1, 2]
a.append(3)
print(a)
a.append((3, 4))
print(a)
b = a.append((3, 4))
print(b)
4、自定义序列对象,实现可切片操作
4.1、自定义可切片对象
自定义可切片对象源码如下:
class Group:
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company_name = company_name
self.staffs = staffs
# 实现这个函数之后,就可以进行切片操作
def __getitem__(self, item):
# 这样返回的是一个列表
return self.staffs[item]
staffs = ["staff1", "staff2", "staff3"]
group = Group(company_name="imooc", group_name="user", staffs=staffs)
sub_group = group[:2]
print(sub_group)
这样写返回的是一个列表,若是需要返回一个可持续切片的类对象,如何操作?
import numbers
class Group:
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company_name = company_name
self.staffs = staffs
# 实现这个函数之后,就可以进行切片操作
# def __getitem__(self, item):
# # 这样返回的是一个列表
# return self.staffs[item]
def __getitem__(self, item):
# 这样返回的是类对象
cls = type(self)
if isinstance(item, slice):
return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
elif isinstance(item, numbers.Integral):
return cls(group_name=self.group_name, company_name=self.group_name, staffs=[self.staffs[item]])
staffs = ["staff1", "staff2", "staff3"]
group = Group(company_name="imooc", group_name="user", staffs=staffs)
sub_group = group[:2]
print(sub_group)
print(sub_group.staffs)
sub_group = group[0]
print(sub_group)
4.2、自定义序列对象
要自定义序列对象,只需要实现Sequence
包含的所有抽象方法,例如__getitem__()
让切片[:2]
,下标[0]
调用、__reversed__()
让reverse()
调用、__iter__()
让for xxx in xxx
调用、__len__()
让len()
调用、__contains__()
让if xxx in xxx
调用
自定义序列对象源码如下:
import numbers
class Group:
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company_name = company_name
self.staffs = staffs
def __reversed__(self):
self.staffs.reverse()
# 切片的关键
def __getitem__(self, item):
# 这样返回的是一个列表
# return self.staffs[item]
# 这样返回的是类对象
cls = type(self)
if isinstance(item, slice):
return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
elif isinstance(item, numbers.Integral):
return cls(group_name=self.group_name, company_name=self.group_name, staffs=[self.staffs[item]])
def __len__(self):
return len(self.staffs)
def __iter__(self):
return iter(self.staffs)
def __contains__(self, item):
if item in self.staffs:
return True
else:
return False
staffs = ["staff1", "staff2", "staff3"]
group = Group(company_name="imooc", group_name="user", staffs=staffs)
sub_group = group[:2]
print(sub_group)
print(sub_group.staffs)
print(len(group))
if "staff1" in group:
print("yes")
for user in group:
print(user)