Разница между контейнером импорта коллекций и контейнером импорта collection.abc - PullRequest
1 голос
/ 27 апреля 2019

Мы можем импортировать Container двумя способами:

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

help функция для обоих Container возвращает одну и ту же документацию.

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__'})

В чем разница между этими двумя импортами? Почему нам разрешено делать оба?

Обновление

Получено предупреждение об устаревании при импорте Container из collections (Python 3.7.3).

Из Python 3.8 он не может быть импортирован напрямую из collections.

>>> from collections import Container

main : 1: DeprecationWarning: использование или импорт АВС из «коллекций» вместо «коллекций.abc» не рекомендуется, и в 3.8 перестанет работать

1 Ответ

1 голос
/ 08 июня 2019

Из документации Python 3 для модуля collections :

Изменено в версии 3.3: Перемещено Коллекции Абстрактные базовые классы в модуль collections.abc.Для обратной совместимости они по-прежнему видны в этом модуле через Python 3.7.Впоследствии они будут удалены полностью.

Эти «Абстрактные базовые классы коллекций» в настоящее время включают 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 их можно импортировать только из «коллекций», а не из «коллекций.abc».

Один из простых способов справиться с этим - блок try / Кроме:

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

Другой часто используемый обходной путь - это условный импорт из collections или collections.abc в зависимости от версии Python.used.

Например, иметь логическое значение 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+ в этом отношении, Python 2 со специальным корпусом выглядит более перспективным, чем Python 3 со специальным корпусом, которыйможно сделать следующим образом:

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

, где логическое значение PY3 может быть получено либо с использованием six:

from six import PY3

, либо с использованием sys.version_info:

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

Приведенный выше подход "попробуй / кроме" кажется еще более надежным (например, онks с Python 3.2 без лишних усилий).

...