Получить объект модуля из кадра стека

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

import sys
from some_other_module import callers_module
assert sys.modules[__name__] is callers_module()

(Это было бы эквивалентно, потому что я могу сгенерировать трассировку стека в функции для этого тестового примера. Импорт нужен просто для того, чтобы сделать этот пример полным и тестируемым, и чтобы callers_module не использовал ярлык с использованием __name__, поскольку он находится в другом модуле .)

Я пробовал это:

import inspect
def callers_module():
  return inspect.currentframe().f_back

Которая получает объект кадра, на котором f_code даст мне объект кода, но я не могу понять, как получить соответствующий модуль или его имя (для использования с sys.modules). Если бы я мог получить объекты функций, они имели бы атрибут __module__ (а также объекты кода), но не присутствовали бы во фрейме. В самом деле, не все объекты кода принадлежат объектам функций, таким как код для моего тестового примера (с assert, приведенным выше). То же самое можно сказать и об объектах фрейма / кода, не имеющих модуля, но многие из них имеют, а в моем случае они будут, так что это не нужно обрабатывать; однако и в этом случае подойдет простое None или исключение.

Такое чувство, что я упускаю что-то простое. Что нужно сделать, чтобы это сработало?


person Community    schedule 04.01.2010    source источник


Ответы (1)


Хотя inspect.getmodule отлично работает, и я действительно искал не в том месте, чтобы найти его, я нашел для себя немного лучшее решение:

def callers_module():
  module_name = inspect.currentframe().f_back.f_globals["__name__"]
  return sys.modules[module_name]

Он по-прежнему использует inspect.currentframe (который я предпочитаю точно такому же sys._getframe), но не вызывает сопоставление имени файла модуля inspect (в inspect.getmodule).

Кроме того, этот вопрос вдохновил на интересный способ управлять __all__:

from export import export

@export
class Example: pass

@export
def example: pass

answer = 42
export.name("answer")

assert __all__ == ["Example", "example", "answer"]
person Community    schedule 06.01.2010
comment
Теперь я хотел бы сделать модули вызываемыми и упростить приведенный выше пример: stackoverflow.com/questions/1060796/callable-modules - person ; 09.01.2010
comment
Будьте осторожны, если ищете строку с именем модуля. Это не будет работать должным образом, если модуль выполняется как сценарий верхнего уровня, потому что тогда __name__ всегда будет __main__. Чтобы охватить все случаи, лучше всего использовать inspect.getmodule().__spec__.name, в котором будет указано настоящее имя модуля, даже если это сценарий верхнего уровня. - person Lucio Paiva; 08.01.2015