Обнаружение кругового импорта

Я работаю с проектом, который содержит приблизительно 30 уникальных модулей. Это не было разработано слишком хорошо, таким образом, распространено, что я создаю круговой импорт при добавлении некоторой новой функциональности к проекту.

Конечно, когда я добавляю круговой импорт, я не знаю о нем. Иногда довольно очевидно, что я сделал круговой импорт, когда я получаю ошибку как AttributeError: 'module' object has no attribute 'attribute' где я ясно определил 'attribute'. Но другие времена, код не выдает исключения из-за способа, которым он используется.

Так, к моему вопросу:

Действительно ли возможно программно обнаружить, когда и где круговой импорт происходит?

Единственное решение, о котором я могу думать до сих пор, состоит в том, чтобы иметь модуль importTracking это содержит dict importingModules, функция importInProgress(file), который увеличивает importingModules[file], и бросает ошибку, если это больше, чем 1, и функция importComplete(file) который постепенно уменьшается importingModules[file]. Все другие модули были бы похожи:

import importTracking
importTracking.importInProgress(__file__)
#module code goes here.
importTracking.importComplete(__file__)

Но это выглядит действительно противным, там получен, чтобы быть лучшим способом сделать это, правильно?

17
задан Peter Mortensen 5 February 2011 в 10:46
поделиться

4 ответа

Чтобы избежать изменения каждого модуля, вы можете закрепить свои функции отслеживания импорта в ловушке импорта или в настраиваемом __ import __ , который можно вставить во встроенные модули - - последнее, на этот раз, может работать лучше, потому что __ import __ вызывается, даже если импортируемый модуль уже находится в sys.modules , что имеет место при циклическом импорте.

Для реализации я бы просто использовал набор модулей «в процессе импорта», что-то вроде (benjaoming edit: вставка рабочего фрагмента, полученного из оригинала):

beingimported = set()
originalimport = __import__
def newimport(modulename, *args, **kwargs):
    if modulename in beingimported:
        print "Importing in circles", modulename, args, kwargs
        print "    Import stack trace -> ", beingimported
        # sys.exit(1) # Normally exiting is a bad idea.
    beingimported.add(modulename)
    result = originalimport(modulename, *args, **kwargs)
    if modulename in beingimported:
        beingimported.remove(modulename)
    return result
import __builtin__
__builtin__.__import__ = newimport
8
ответ дан 30 November 2019 в 14:33
поделиться

Циклический импорт в Python не похож на PHP.

Импортированные модули Python загружаются в первый раз в «обработчик» импорта и хранятся там на протяжении всего процесса. Этот обработчик назначает имена в локальном пространстве имен всему, что импортируется из этого модуля, для каждого последующего импорта.Модуль уникален, и ссылка на это имя модуля всегда будет указывать на один и тот же загруженный модуль, независимо от того, куда он был импортирован.

Итак, если у вас есть циклический импорт модуля, загрузка каждого файла будет происходить один раз, а затем каждый модуль будет иметь имена, относящиеся к другому модулю, созданному в его пространстве имен.

Конечно, могут возникнуть проблемы при обращении к конкретным именам в обоих модулях (когда циклический импорт происходит ДО определений классов / функций, на которые есть ссылки в импорте противоположных модулей), но вы получите сообщение об ошибке, если это бывает.

1
ответ дан 30 November 2019 в 14:33
поделиться

Не весь циклический импорт является проблемой, как вы обнаружили, когда исключение не генерируется.

Когда они представляют собой проблему, вы получите исключение при следующей попытке запустить любой из ваших тестов. В этом случае вы можете изменить код.

Я не вижу необходимости в каких-либо изменениях в этой ситуации.

Пример, когда это не проблема:

a.py

import b
a = 42
def f():
  return b.b

b.py

import a
b = 42
def f():
  return a.a
1
ответ дан 30 November 2019 в 14:33
поделиться

import использует __ builtin __.__ import __ () , поэтому, если вы установите его monkeypatch, тогда каждый импорт повсюду будет принимать изменения. Обратите внимание, что циклический импорт не обязательно является проблемой .

1
ответ дан 30 November 2019 в 14:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: