Метод импорта из подмодуля Python в __init__, но не сам подмодуль - PullRequest
4 голосов
/ 14 июня 2019

У меня есть модуль Python со следующей структурой:

mymod/
    __init__.py
    tools.py
# __init__.py
from .tools import foo
# tools.py
def foo():
    return 42

Теперь, когда import mymod, я вижу, что он имеет следующие члены:

mymod.foo()
mymod.tools.foo()

Я не хочу последнего, хотя;он просто загрязняет пространство имен.

Как ни странно, если tools.py называется foo.py, вы получаете то, что хотите:

mymod.foo()

(Очевидно, это работает, только если есть только одинфункция для файла.)

Как избежать импорта tools?Обратите внимание, что ввод foo() в __init__.py не вариант.(На самом деле, существует много функций, таких как foo, которые абсолютно загромождают файл.)

Ответы [ 3 ]

4 голосов
/ 14 июня 2019

Наличие атрибута mymod.tools имеет решающее значение для поддержания надлежащего функционирования системы импорта.Один из обычных инвариантов импорта Python состоит в том, что если модуль x.y зарегистрирован в sys.modules, то модуль x имеет атрибут y, относящийся к модулю x.y.В противном случае такие вещи, как

import x.y
x.y.y_function()

, ломаются, и в зависимости от версии Python, даже

from x import y

может сломаться.Даже если вы не думаете, что делаете что-то, что могло бы сломаться, другие инструменты и модули полагаются на эти инварианты, и попытка удалить атрибут приводит к множеству проблем совместимости, которые никоим образом не стоят этого.


Попытка сделать так, чтобы tools не отображался в пространстве имен вашего модуля mymod, все равно, что пытаться не отображать атрибуты "private" (начальное подчеркивание) в пространствах имен ваших объектов.Это не то, как Python предназначен для работы, и попытка заставить его работать таким образом, вызывает больше проблем, чем решает.

Соглашение с подчеркиванием не только для переменных экземпляра.Вы можете пометить ваш tools модуль подчеркиванием, переименовав его в _tools.Это предотвратит его захват при from mymod import * импорте (если вы явно не поместите его в список __all__), и это изменит способ обработки IDE и линтерами попыток прямого доступа к нему.

0 голосов
/ 14 июня 2019

Вы не импортируете модуль tools, он доступен только при импорте пакета, как вы делаете:

import mymod

У вас будет доступ ко всему, что определено в файле __init__ ивсе модули этого пакета:

import mymod

# Reference a module
mymod.tools

# Reference a member of a module
mymod.tools.foo

# And any other modules from this package
mymod.tools.subtools.func

Когда вы импортируете foo из __init__, вы просто делаете foo доступным там, как если бы вы его определили, но, конечно, вы определилиэто в tools, который является способом организации вашего пакета, так что теперь, так как вы импортировали его в __init__, вы можете:

import mymod

mymod.foo()

Или вы можете импортировать только foo:

from mymod import foo

foo()

Но вы можете импортировать foo, не делая его доступным внутри __init__, вы можете сделать следующее, точно такое же, как в примере выше:

from mymod.tools import foo

foo()

Вы можете использовать оба подхода,они оба правы, во всех этих примерах вы не «загромождаете файл», поскольку вы можете видеть, что доступ к foo с использованием mymod.tools.foo имеет пространство имен, так что вы можете иметь несколько foo, определенных в других модулях.

0 голосов
/ 14 июня 2019

Попробуйте добавить это в __init__.py файл:

from .tools import foo
del tools
...