• Python创建容器和集合之源码分析


      _collections_abc.py文件中提供了许多抽象基类,这些类将集合分解成许多互相独立的属性集
      __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",
                 ]

      接下来对__all__中的部分基类作说明

    只包含一个特殊方法的基类

      以下基类都包含_check_methods方法,检查类中是否实现特定函数

    def _check_methods(C, *methods):
        mro = C.__mro__
        for method in methods:
            for B in mro:
                if method in B.__dict__:
                    if B.__dict__[method] is None:
                        return NotImplemented
                    break
            else:
                return NotImplemented
        return True

    1. Hashable

      Hashable基类要求子类实现__hash__方法,hash函数需要使用这个方法,如果这个方法被实现了就意味着当前对象的不可变的

    class Hashable(metaclass=ABCMeta):
    
        __slots__ = ()
    
        @abstractmethod
        def __hash__(self):
            return 0
     
        @classmethod
        def __subclasshook__(cls, C):
            if cls is Hashable:
                return _check_methods(C, "__hash__")
            return NotImplemented

    2. Iterable

      Iterable基类要求子类实现__iter__方法, for语句,生成器表达式和iter()都需要使用这个函数 

    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

    3. Iterator

      Iterator基类继承Iterable类,要求子类实现__next__方法,迭代对象的实现需要实现该函数

    class Iterator(Iterable):
    
        __slots__ = ()
    
        @abstractmethod
        def __next__(self):
            'Return the next item from the iterator. When exhausted, raise StopIteration'
            raise StopIteration
    
        def __iter__(self):
            return self
    
        @classmethod
        def __subclasshook__(cls, C):
            if cls is Iterator:
                return _check_methods(C, '__iter__', '__next__')
            return NotImpleented

    4. Sized

      Sized基类要求子类实现__len__方法,len()函数需要使用这个方法,它也很稳妥地实现了__bool__方法

    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

    5. Container

      Container基类需要子类实现__contains__()方法,这个方法实现了in运算符

    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

    6. Collection

      Collection类多继承Sized、Iterable、Container类

    class Collection(Sized, Iterable, Container):
    
        __slots__ = ()
    
        @classmethod
        def __subclasshook__(cls, C):
            if cls is Collection:
                return _check_methods(C,  "__len__", "__iter__", "__contains__")
            return NotImplemented

    7. Callable

      Callable基类需要子类实现__call__方法,可调用对象的实现需要使用__call__方法

    class Callable(metaclass=ABCMeta):
    
        __slots__ = ()
    
        @abstractmethod
        def __call__(self, *args, **kwds):
            return False
    
        @classmethod
        def __subclasshook__(cls, C):
            if cls is Callable:
                return _check_methods(C, "__call__")
            return NotImplemented

    代表性的复合基类

    1. class Set(Collection)

    class Set(Collection):
    
        """A set is a finite, iterable container.
    
        This class provides concrete generic implementations of all
        methods except for __contains__, __iter__ and __len__.
    
        To override the comparisons (presumably for speed, as the
        semantics are fixed), redefine __le__ and __ge__,
        then the other operations will automatically follow suit.
        """
    
        __slots__ = ()
    
        def __le__(self, other):
            if not isinstance(other, Set):
                return NotImplemented
            if len(self) > len(other):
                return False
            for elem in self:
                if elem not in other:
                    return False
            return True
    
        def __lt__(self, other):
            if not isinstance(other, Set):
                return NotImplemented
            return len(self) < len(other) and self.__le__(other)
    
        def __gt__(self, other):
            if not isinstance(other, Set):
                return NotImplemented
            return len(self) > len(other) and self.__ge__(other)
    
        def __ge__(self, other):
            if not isinstance(other, Set):
                return NotImplemented
            if len(self) < len(other):
                return False
            for elem in other:
                if elem not in self:
                    return False
            return True
    
        def __eq__(self, other):
            if not isinstance(other, Set):
                return NotImplemented
            return len(self) == len(other) and self.__le__(other)
    
        @classmethod
        def _from_iterable(cls, it):
            '''Construct an instance of the class from any iterable input.
    
            Must override this method if the class constructor signature
            does not accept an iterable for an input.
            '''
            return cls(it)
    
        def __and__(self, other):
            if not isinstance(other, Iterable):
                return NotImplemented
            return self._from_iterable(value for value in other if value in self)
    
        __rand__ = __and__
    
        def isdisjoint(self, other):
            'Return True if two sets have a null intersection.'
            for value in other:
                if value in self:
                    return False
            return True
    
        def __or__(self, other):
            if not isinstance(other, Iterable):
                return NotImplemented
            chain = (e for s in (self, other) for e in s)
            return self._from_iterable(chain)
    
        __ror__ = __or__
    
        def __sub__(self, other):
            if not isinstance(other, Set):
                if not isinstance(other, Iterable):
                    return NotImplemented
                other = self._from_iterable(other)
            return self._from_iterable(value for value in self
                                       if value not in other)
    
        def __rsub__(self, other):
            if not isinstance(other, Set):
                if not isinstance(other, Iterable):
                    return NotImplemented
                other = self._from_iterable(other)
            return self._from_iterable(value for value in other
                                       if value not in self)
    
        def __xor__(self, other):
            if not isinstance(other, Set):
                if not isinstance(other, Iterable):
                    return NotImplemented
                other = self._from_iterable(other)
            return (self - other) | (other - self)
    
        __rxor__ = __xor__
    
        def _hash(self):
            """Compute the hash value of a set.
    
            Note that we don't define __hash__: not all sets are hashable.
            But if you define a hashable set type, its __hash__ should
            call this function.
    
            This must be compatible __eq__.
    
            All sets ought to compare equal if they contain the same
            elements, regardless of how they are implemented, and
            regardless of the order of the elements; so there's not much
            freedom for __eq__ or __hash__.  We match the algorithm used
            by the built-in frozenset type.
            """
            MAX = sys.maxsize
            MASK = 2 * MAX + 1
            n = len(self)
            h = 1927868237 * (n + 1)
            h &= MASK
            for x in self:
                hx = hash(x)
                h ^= (hx ^ (hx << 16) ^ 89869747)  * 3644798167
                h &= MASK
            h = h * 69069 + 907133923
            h &= MASK
            if h > MAX:
                h -= MASK + 1
            if h == -1:
                h = 590923713
            return h
    View Code

      通过源码看到Set类实现了用于set类型的比较操作和算术运算符的实现:

      __le__  __lt__  __gt__  __ge__  __eq__

      _from_iterable(如果类的构造函数不接受iterable作为参数的话必须重写该方法)

      __and__  __rand__  __or__   __ror__ 

      __sub__  __rsub__  __xor__  __rxor__

      _hash(__hash__()应该调用该函数)

    2. class MutableSet(Set)

    class MutableSet(Set):
        """A mutable set is a finite, iterable container.
    
        This class provides concrete generic implementations of all
        methods except for __contains__, __iter__, __len__,
        add(), and discard().
    
        To override the comparisons (presumably for speed, as the
        semantics are fixed), all you have to do is redefine __le__ and
        then the other operations will automatically follow suit.
        """
    
        __slots__ = ()
    
        @abstractmethod
        def add(self, value):
            """Add an element."""
            raise NotImplementedError
    
        @abstractmethod
        def discard(self, value):
            """Remove an element.  Do not raise an exception if absent."""
            raise NotImplementedError
    
        def remove(self, value):
            """Remove an element. If not a member, raise a KeyError."""
            if value not in self:
                raise KeyError(value)
            self.discard(value)
    
        def pop(self):
            """Return the popped value.  Raise KeyError if empty."""
            it = iter(self)
            try:
                value = next(it)
            except StopIteration:
                raise KeyError
            self.discard(value)
            return value
    
        def clear(self):
            """This is slow (creates N new iterators!) but effective."""
            try:
                while True:
                    self.pop()
            except KeyError:
                pass
    
        def __ior__(self, it):
            for value in it:
                self.add(value)
            return self
    
        def __iand__(self, it):
            for value in (self - it):
                self.discard(value)
            return self
    
        def __ixor__(self, it):
            if it is self:
                self.clear()
            else:
                if not isinstance(it, Set):
                    it = self._from_iterable(it)
                for value in it:
                    if value in self:
                        self.discard(value)
                    else:
                        self.add(value)
            return self
    
        def __isub__(self, it):
            if it is self:
                self.clear()
            else:
                for value in it:
                    self.discard(value)
            return self
    View Code

      子类需要实现两个@abstractmethod方法,add和discard

      具体方法有:

      add  discard  remove  pop  clear  

      __ior__  __ixor__  __isub__

    3. class Mapping(Collection)

      首先通过源码看一下KeysView、ItemsView和ValuesView的实现

    class MappingView(Sized):
    
        __slots__ = '_mapping',
    
        def __init__(self, mapping):
            self._mapping = mapping
    
        def __len__(self):
            return len(self._mapping)
    
        def __repr__(self):
            return '{0.__class__.__name__}({0._mapping!r})'.format(self)
    
    
    class KeysView(MappingView, Set):
    
        __slots__ = ()
    
        @classmethod
        def _from_iterable(self, it):
            return set(it)
    
        def __contains__(self, key):
            return key in self._mapping
    
        def __iter__(self):
            yield from self._mapping
    
    
    class ItemsView(MappingView, Set):
    
        __slots__ = ()
    
        @classmethod
        def _from_iterable(self, it):
            return set(it)
    
        def __contains__(self, item):
            key, value = item
            try:
                v = self._mapping[key]
            except KeyError:
                return False
            else:
                return v is value or v == value
    
        def __iter__(self):
            for key in self._mapping:
                yield (key, self._mapping[key])
    
    class ValuesView(MappingView):
    
        __slots__ = ()
    
        def __contains__(self, value):
            for key in self._mapping:
                v = self._mapping[key]
                if v is value or v == value:
                    return True
            return False
    
        def __iter__(self):
            for key in self._mapping:
                yield self._mapping[key]
    View Code

      Mapping源码实现

    class Mapping(Collection):
    
        __slots__ = ()
    
        """A Mapping is a generic container for associating key/value
        pairs.
    
        This class provides concrete generic implementations of all
        methods except for __getitem__, __iter__, and __len__.
    
        """
    
        @abstractmethod
        def __getitem__(self, key):
            raise KeyError
    
        def get(self, key, default=None):
            'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
            try:
                return self[key]
            except KeyError:
                return default
    
        def __contains__(self, key):
            try:
                self[key]
            except KeyError:
                return False
            else:
                return True
    
        def keys(self):
            "D.keys() -> a set-like object providing a view on D's keys"
            return KeysView(self)
    
        def items(self):
            "D.items() -> a set-like object providing a view on D's items"
            return ItemsView(self)
    
        def values(self):
            "D.values() -> an object providing a view on D's values"
            return ValuesView(self)
    
        def __eq__(self, other):
            if not isinstance(other, Mapping):
                return NotImplemented
            return dict(self.items()) == dict(other.items())
    
        __reversed__ = None
    View Code

    4. class MutableMapping(Mapping)

    class MutableMapping(Mapping):
    
        __slots__ = ()
    
        """A MutableMapping is a generic container for associating
        key/value pairs.
    
        This class provides concrete generic implementations of all
        methods except for __getitem__, __setitem__, __delitem__,
        __iter__, and __len__.
    
        """
    
        @abstractmethod
        def __setitem__(self, key, value):
            raise KeyError
    
        @abstractmethod
        def __delitem__(self, key):
            raise KeyError
    
        __marker = object()
    
        def pop(self, key, default=__marker):
            '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
              If key is not found, d is returned if given, otherwise KeyError is raised.
            '''
            try:
                value = self[key]
            except KeyError:
                if default is self.__marker:
                    raise
                return default
            else:
                del self[key]
                return value
    
        def popitem(self):
            '''D.popitem() -> (k, v), remove and return some (key, value) pair
               as a 2-tuple; but raise KeyError if D is empty.
            '''
            try:
                key = next(iter(self))
            except StopIteration:
                raise KeyError
            value = self[key]
            del self[key]
            return key, value
    
        def clear(self):
            'D.clear() -> None.  Remove all items from D.'
            try:
                while True:
                    self.popitem()
            except KeyError:
                pass
    
        def update(*args, **kwds):
            ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
                If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
                If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
                In either case, this is followed by: for k, v in F.items(): D[k] = v
            '''
            if not args:
                raise TypeError("descriptor 'update' of 'MutableMapping' object "
                                "needs an argument")
            self, *args = args
            if len(args) > 1:
                raise TypeError('update expected at most 1 arguments, got %d' %
                                len(args))
            if args:
                other = args[0]
                if isinstance(other, Mapping):
                    for key in other:
                        self[key] = other[key]
                elif hasattr(other, "keys"):
                    for key in other.keys():
                        self[key] = other[key]
                else:
                    for key, value in other:
                        self[key] = value
            for key, value in kwds.items():
                self[key] = value
    
        def setdefault(self, key, default=None):
            'D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D'
            try:
                return self[key]
            except KeyError:
                self[key] = default
            return default
    View Code

    5. class Sequence(Reversible, Collection)

    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.
            '''
            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:
                    if self[i] == 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 == value)
    View Code

    6. class 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
    View Code
  • 相关阅读:
    preg_match()
    Ubuntu解压缩zip,tar,tar.gz,tar.bz2文件命令
    Couchbase集群
    画图工具
    谷歌打不开
    筛选重复数据的方法
    div垂直居中的N种方法 单行/多行文字(未知高度/固定高度)
    ie6 ol 序列号 bug
    IE6、7下li元素的子元素为dl,ul,ol时产生的bug
    ie6 line-height bug解决办法
  • 原文地址:https://www.cnblogs.com/xiaobingqianrui/p/8613100.html
Copyright © 2020-2023  润新知