> **Источник:** https://python-all.ru/2.7/library/imputil.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 31.3. [`imputil`](https://python-all.ru/2.7/library/imputil.html#module-imputil) – Утилиты импорта

Устарело с версии 2.6: Модуль [`imputil`](https://python-all.ru/2.7/library/imputil.html#module-imputil) удалён в Python 3.

Этот модуль предоставляет очень удобный и полезный механизм для настраиваемых [`import`](https://python-all.ru/2.7/reference/simple_stmts.html#import) хуков. По сравнению со старым модулем `ihooks`, [`imputil`](https://python-all.ru/2.7/library/imputil.html#module-imputil) использует гораздо более простой и прямой подход к настраиваемым функциям [`import`](https://python-all.ru/2.7/reference/simple_stmts.html#import).

#### `class imputil.ImportManager([fs_imp])`

Управляет процессом импорта.

#### `install([namespace])`

Устанавливает этот ImportManager в указанное пространство имён.

#### `uninstall()`

Восстанавливает предыдущий механизм импорта.

#### `add_suffix(suffix, importFunc)`

Не документировано.

#### `class imputil.Importer`

Базовый класс для замены стандартных функций импорта.

#### `import_top(name)`

Импортирует модуль верхнего уровня.

#### `get_code(parent, modname, fqname)`

Находит и извлекает код для указанного модуля.

*parent* указывает родительский модуль для определения контекста импорта. Может быть `None`, что означает отсутствие конкретного контекста поиска.

*modname* указывает отдельный модуль (не составное имя) внутри родительского.

*fqname* указывает полное квалифицированное имя модуля. Это (потенциально) составное имя от “корня” пространства имён модулей до modname.

Если родитель отсутствует, то modname == fqname.

Этот метод должен возвращать `None` или кортеж из 3 элементов.

> - Если модуль не найден, следует вернуть `None`.
> - Первый элемент кортежа из 2 или 3 элементов должен быть целым числом 0 или 1, указывающим, является ли найденный модуль пакетом.
> - Второй элемент – это объект кода для модуля (он будет выполнен в пространстве имён нового модуля). Этот элемент также может быть полностью загруженным объектом модуля (например, загруженным из динамической библиотеки).
> - Третий элемент – это словарь пар имя/значение, которые будут вставлены в новый модуль до выполнения объекта кода. Это предусмотрено на случай, если код модуля ожидает определённые значения (например, где был найден модуль). Когда второй элемент является объектом модуля, эти имена/значения будут вставлены *после* загрузки/инициализации модуля.

#### `class imputil.BuiltinImporter`

Эмулирует механизм импорта для встроенных и замороженных модулей. Это подкласс класса [`Importer`](https://python-all.ru/2.7/library/imputil.html#imputil.Importer).

#### `get_code(parent, modname, fqname)`

Не документировано.

#### `imputil.py_suffix_importer(filename, finfo, fqname)`

Не документировано.

#### `class imputil.DynLoadSuffixImporter([desc])`

Не документировано.

#### `import_file(filename, finfo, fqname)`

Без документации.

## 31.3.1. Примеры

Это повторная реализация иерархического импорта модулей.

Этот код предназначен для чтения, а не для выполнения. Однако он работает – всё, что нужно сделать для его включения, – это «import knee».

(Название – это игра слов, отсылающая к более громоздкому предшественнику этого модуля – «ni».)

```python
import sys, imp, __builtin__

# Замена для __import__()
def import_hook(name, globals=None, locals=None, fromlist=None):
    parent = determine_parent(globals)
    q, tail = find_head_package(parent, name)
    m = load_tail(q, tail)
    if not fromlist:
        return q
    if hasattr(m, "__path__"):
        ensure_fromlist(m, fromlist)
    return m

def determine_parent(globals):
    if not globals or  not globals.has_key("__name__"):
        return None
    pname = globals['__name__']
    if globals.has_key("__path__"):
        parent = sys.modules[pname]
        assert globals is parent.__dict__
        return parent
    if '.' in pname:
        i = pname.rfind('.')
        pname = pname[:i]
        parent = sys.modules[pname]
        assert parent.__name__ == pname
        return parent
    return None

def find_head_package(parent, name):
    if '.' in name:
        i = name.find('.')
        head = name[:i]
        tail = name[i+1:]
    else:
        head = name
        tail = ""
    if parent:
        qname = "%s.%s" % (parent.__name__, head)
    else:
        qname = head
    q = import_module(head, qname, parent)
    if q: return q, tail
    if parent:
        qname = head
        parent = None
        q = import_module(head, qname, parent)
        if q: return q, tail
    raise ImportError("No module named " + qname)

def load_tail(q, tail):
    m = q
    while tail:
        i = tail.find('.')
        if i < 0: i = len(tail)
        head, tail = tail[:i], tail[i+1:]
        mname = "%s.%s" % (m.__name__, head)
        m = import_module(head, mname, m)
        if not m:
            raise ImportError("No module named " + mname)
    return m

def ensure_fromlist(m, fromlist, recursive=0):
    for sub in fromlist:
        if sub == "*":
            if not recursive:
                try:
                    all = m.__all__
                except AttributeError:
                    pass
                else:
                    ensure_fromlist(m, all, 1)
            continue
        if sub != "*" and not hasattr(m, sub):
            subname = "%s.%s" % (m.__name__, sub)
            submod = import_module(sub, subname, m)
            if not submod:
                raise ImportError("No module named " + subname)

def import_module(partname, fqname, parent):
    try:
        return sys.modules[fqname]
    except KeyError:
        pass
    try:
        fp, pathname, stuff = imp.find_module(partname,
                                              parent and parent.__path__)
    except ImportError:
        return None
    try:
        m = imp.load_module(fqname, fp, pathname, stuff)
    finally:
        if fp: fp.close()
    if parent:
        setattr(parent, partname, m)
    return m

# Замена для reload()
def reload_hook(module):
    name = module.__name__
    if '.' not in name:
        return import_module(name, name, None)
    i = name.rfind('.')
    pname = name[:i]
    parent = sys.modules[pname]
    return import_module(name[i+1:], name, parent)

# Сохранить исходные хуки
original_import = __builtin__.__import__
original_reload = __builtin__.reload

# Теперь установить наши хуки
__builtin__.__import__ = import_hook
__builtin__.reload = reload_hook
```

Также см. модуль `importers` (находится в `Demo/imputil/` в дистрибутиве исходного кода Python) для дополнительных примеров.
