Получить объект модуля из стекового фрейма - PullRequest
8 голосов
/ 04 января 2010

Учитывая объект кадра, мне нужно получить соответствующий объект модуля. Другими словами, реализуйте 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__ (а также объекты кода), но его нет в кадре. Действительно, не все объекты кода принадлежат функциональным объектам, таким как код для моего теста (с утверждением выше). То же самое можно сказать о объектах frame / code, не имеющих модуля - но многие из них имеют, и в моем случае они будут, так что это не нужно обрабатывать; тем не менее, простое None или исключение в этом случае тоже подойдут.

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

Ответы [ 2 ]

6 голосов
/ 06 января 2010

Хотя 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"]
2 голосов
/ 04 января 2010
import inspect
def callers_module():
   module = inspect.getmodule(inspect.currentframe().f_back)
   return module
...