Как предотвратить одновременный импорт модуля?

При написании модулей python существует ли способ запретить им дважды импортировать коды клиентов? Так же, как файлы заголовков c/С++:

#ifndef XXX
#define XXX
...
#endif

Большое спасибо!

Ответ 1

Модули Python не импортируются несколько раз. Просто запуск импорта два раза не перезагрузит модуль. Если вы хотите, чтобы он был перезагружен, вам нужно использовать оператор reload. Здесь демонстрационная версия

foo.py - это модуль с единственной линией

print "I am being imported"

И вот сценарий нескольких попыток импорта.

   >>> import foo
   Hello, I am being imported
   >>> import foo # Will not print the statement
   >>> reload(foo) # Will print it again
   Hello, I am being imported

Ответ 2

Импорт кэшируется и запускается только один раз. Дополнительный импорт ограничивает время поиска в sys.modules.

Ответ 3

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

Однако есть несколько недостатков, которые стоит отметить:

  • Импорт основного модуля как обычного модуля эффективно создает два экземпляра одного и того же модуля под разными именами.

    Это происходит потому, что во время запуска программы основной модуль настроен с именем __main__. Таким образом, при импорте его как обычного модуля Python не обнаруживает его в sys.modules и импортирует его снова, но со своим собственным именем во второй раз.

    Рассмотрим файл /tmp/a.py со следующим содержимым:

    # /tmp/a.py
    import sys
    
    print "%s executing as %s, recognized as %s in sys.modules" % (__file__, __name__, sys.modules[__name__])
    import b
    

    Другой файл /tmp/b.py имеет единственный оператор import для a.py(import a).
    Выполнение /tmp/a.py приводит к следующему выводу:

    [email protected]:/tmp$ python a.py
    a.py executing as __main__, recognized as <module '__main__' from 'a.py'> in sys.modules
    /tmp/a.pyc executing as a, recognized as <module 'a' from '/tmp/a.pyc'> in sys.modules
    

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

  • В этом ответе указаны еще два возможных сценария:

    • Несколько разных операторов импорта, использующих разные записи в sys.path, ведущие к одному и тому же модулю.
    • Попытка другого импорта модуля после того, как предыдущий провалился на полпути.