Похоже, что это (относительно безвредная) ошибка, вызванная оптимизацией numpy
, вставленной во избежание затрат на импорт подпакета testing
, в то же время предоставляя testing
и Tester
в качестве атрибутов root numpy
package.
Оптимизация использует уровень модуля __getattr__
(доступен только на Python 3.7+, поэтому он не используется на 3.6 и более ранних версиях), чтобы импортировать их, только если они явный доступ (в этот момент testing
становится реальным атрибутом numpy
, поскольку дочерние модули и пакеты присоединяются к своим родителям в качестве атрибутов при импорте автоматически), но чтобы продолжать притворяться, что они импортированы с нетерпением, он также определяет модуль -level __dir__
, который притворяется, что они уже существуют:
def __dir__():
return list(globals().keys()) + ['Tester', 'testing']
Недостаток в том, что, если numpy.testing
импортируется (либо явно, либо неявно через хук __getattr__
), то он уже появляется в globals()
, поэтому добавление ['Tester', 'testing']
к list
добавляет вторую копию 'testing'
к результату dir
.
Они могут тривиально исправить это путем дедупликации (до преобразования в list
или просто без преобразования, поскольку dir
уже задокументировано для автоматического выполнения преобразования ), а не конкатенации после, например:
def __dir__():
return globals().keys() | {'Tester', 'testing'}
но это не серьезная ошибка; код, который ломается из-за того, что dir
дает удвоенный результат, вероятно, довольно хрупок и глючит из get- go.
Полное объяснение этой оптимизации приведено в комментариях источника:
# Importing Tester requires importing all of UnitTest which is not a
# cheap import Since it is mainly used in test suits, we lazy import it
# here to save on the order of 10 ms of import time for most users
#
# The previous way Tester was imported also had a side effect of adding
# the full `numpy.testing` namespace
#
# module level getattr is only supported in 3.7 onwards
# https://www.python.org/dev/peps/pep-0562/
На 3.6 и более ранних версиях путь к коду, определяющий __getattr__
и __dir__
, пропускается, и все, что он делает, это:
# We don't actually use this ourselves anymore, but I'm not 100% sure that
# no-one else in the world is using it (though I hope not)
from .testing import Tester
, что означает, что testing
и Tester
являются "настоящими" атрибутами из get- go, и ошибка не возникает.