Как я могу создать модуль Python, который возвращает другой модуль - PullRequest
3 голосов
/ 13 апреля 2019

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

python>
import foo
import fake_foo

help(foo) == help(fake_foo)

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

В случае, если было неясно, приведенный ниже код не работает не по очевидным причинам: load_source возвращает модуль, но не может сказать python загрузить его в текущий модуль.

# fake_foo/__init__.py

import imp
imp.load_source('foo', '/path/to/foo')

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

PS. Мне понадобится код, который будет работать с py27, py35 +, что высока вероятность это потребовало бы другой логики, но как только я настрою ее на одну версию, не составит труда найти аналогичные способы для других версий.

1 Ответ

5 голосов
/ 13 апреля 2019

Это на самом деле тривиально.Просто замените sys.modules.

В шим-модуле:

# mod1.py
import sys
import mod2

sys.modules["mod1"] = mod2

В реальном модуле:

# mod2.py
var = 'hello'

Демонстрация:

>>> import mod1
>>> mod1
<module 'mod2' from 'mod2.py'>
>>> mod1.var
'potato'

Это может показаться хакерским, но это функция в Python - механизм импорта намеренно допускает такой трюк.

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

От GvR: https://mail.python.org/pipermail/python-ideas/2012-May/014969.html

...