from collections import Container 和 from collections.abc import Container 的区别

Difference between from collections import Container and from collections.abc import Container

我们可以通过两种方式导入Container

  1. from collections import Container
  2. from collections.abc import Container

help 函数用于 Container returns 相同的文档。

help(collections.Container):

Help on class Container in module collections.abc:

class Container(builtins.object)
 |  Methods defined here:
 |  
 |  __contains__(self, x)
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  __subclasshook__(C) from abc.ABCMeta
 |      Abstract classes can override this to customize issubclass().
 |      
 |      This is invoked early on by abc.ABCMeta.__subclasscheck__().
 |      It should return True, False or NotImplemented.  If it returns
 |      NotImplemented, the normal algorithm is used.  Otherwise, it
 |      overrides the normal algorithm (and the outcome is cached).
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __abstractmethods__ = frozenset({'__contains__'})

help(collections.abc.Container):

Help on class Container in module collections.abc:

class Container(builtins.object)
 |  Methods defined here:
 |  
 |  __contains__(self, x)
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  __subclasshook__(C) from abc.ABCMeta
 |      Abstract classes can override this to customize issubclass().
 |      
 |      This is invoked early on by abc.ABCMeta.__subclasscheck__().
 |      It should return True, False or NotImplemented.  If it returns
 |      NotImplemented, the normal algorithm is used.  Otherwise, it
 |      overrides the normal algorithm (and the outcome is cached).
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __abstractmethods__ = frozenset({'__contains__'})

这两个导入有什么区别?为什么我们可以两者兼顾?

更新

collections (Python 3.7.3) 导入 Container 时收到弃用警告。

Python 3.8无法直接从collections导入。

>>> from collections import Container

main:1: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working

来自Python 3 documentation for the collections module

Changed in version 3.3: Moved Collections Abstract Base Classes to the collections.abc module. For backwards compatibility, they continue to be visible in this module through Python 3.7. Subsequently, they will be removed entirely.

这些 "Collections Abstract Base Classes" 目前包括 AsyncGenerator, AsyncIterable, AsyncIterator, Awaitable, Bytestring, Callable, Collection, Container, Coroutine, Generator, Hashable, ItemsView, Iterable, Iterator, KeysView, Mapping, MappingView, MutableMapping, MutableSequence, MutableSet, Reversible, Sequence, Set, Sized, ValuesView.

在 Python 3.8 中,从 collections 导入它们将停止工作。 在 Python 3.3 到 3.7 中,它们可以从 collections 或者 来自 collections.abc(它给出完全相同的 类)。 在 Python 3.7 中,从 collections 导入它们会打印一个 弃用警告,因为 Python 3.8 即将到来。

在 Python 2 中它们只能从 'collections' 导入, 不是来自 'collections.abc'.

一个简单的处理方法是 try/except 块:

try:  # works in Python >= 3.3
    from collections.abc import Sequence
except ImportError:  # Python 2, Python <= 3.2
    from collections import Sequence

另一种常用的解决方法是有条件地 从 collectionscollections.abc 导入取决于 在正在使用的 Python 版本上。

例如,有一个 PY2 布尔值并执行:

if PY2:
    from collections import Sequence
else:
    from collections.abc import Sequence

此布尔值通常使用 six:

获得
from six import PY2

或使用sys.version_info:

import sys
PY2 = int(sys.version_info[0]) == 2

如果我们预计 Python 4 可能像 Python 3.3+ 那样工作 在这方面,special-casing Python 2 似乎更 future-proof 比 special-casing Python 3,可以按如下方式完成:

if PY3:
    from collections.abc import Sequence
else:
    from collections import Sequence

其中可以使用 six:

获得 PY3 布尔值
from six import PY3

或使用sys.version_info:

import sys
PY3 = int(sys.version_info[0]) == 3

上面的 try/except 方法似乎更可靠 (例如,它无需额外的努力即可与 Python 3.2 一起使用)。