Python中的序列


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又继承了ReversibleCollection两个类

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又继承了SizedIterableContainer三个类

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)


文章作者: 星凌映雪
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 星凌映雪 !
评论
 上一篇
python安装各种第三方库的方法 python安装各种第三方库的方法
一、使用pip安装 由于历史的原因,Python有两个著名的包管理工具easy_install和pip,在Python2.7的安装包中,easy_install是默认安装的,而pip需要我们手动进行安装。随着Python版本的提高,easy
2020-05-19
下一篇 
Python中的字符串总结 Python中的字符串总结
在Python中,字符串除了支持序列通用操作(包括双向索引、比较大小、计算长度、元素访问、切片、成员测试等)以外,还支持一些特有的用法,例如字符串格式化、查找、替换、排版等。但由于字符串属于不可变有序序列,不能直接对字符串对象进行元素增加
2020-05-17
  目录