Как получить ссылку на текущие атрибуты модуля в Python

119

То, что я пытаюсь сделать, в командной строке будет выглядеть так:

>>> import mymodule
>>> names = dir(mymodule)

Как я могу получить ссылку на все имена, определенные mymoduleвнутри mymoduleсебя?

Что-то вроде этого:

# mymodule.py
names = dir(__thismodule__)
guillermooo
источник
пожалуйста, также проверьте stackoverflow.com/questions/3281300/…
ksridhar 07

Ответы:

135

Просто используйте globals ()

globals () - возвращает словарь, представляющий текущую глобальную таблицу символов. Это всегда словарь текущего модуля (внутри функции или метода это модуль, в котором он определен, а не модуль, из которого он вызывается).

http://docs.python.org/library/functions.html#globals

Мацей Пастернацки
источник
4
Есть ли способ получить доступ к gloabals () вызывающего модуля вместо определяющего модуля?
dimo414
9
Вы можете попробовать получить глобальные переменные вызывающего абонента из модуля трассировки ( docs.python.org/library/traceback.html ), но это попадает на территорию темной магии. Я не знаю, что вы пытаетесь сделать, но вы можете пересмотреть свой дизайн, если вам это нужно.
Maciej Pasternacki
Классический случай: «Мне нужен X (чтобы выполнить Y) -> Вам не нужен X, вам нужен Z». Хотя мне нужен Х! Без обид, я просто нахожу это забавным, и ответ, получивший наибольшее количество голосов, дает мне ответ, который мне нужен :)
павамой
Важно отметить, что globals () может возвращать неверный результат, поскольку это зависит от контекста, в котором вызывается. Например, если сделать вызов из функции класса, то она вернет глобальный контекст, связанный с классом, а не текущий контекст модуля, что существенно отличается. Даже если выполнить вызов из бесплатной функции, он может вернуть другой глобальный контекст модуля, в зависимости от того, как функция была импортирована.
Andry
163

Как упоминалось ранее, globals дает вам словарь, в отличие от dir (), который дает вам список имен, определенных в модуле. Обычно я это вижу так:

import sys
dir(sys.modules[__name__])
jamesls
источник
2
Я собирался добавить комментарий о том, что это не сработает для « основного » модуля (так называется модуль, запускаемый на терминале), потому что он, похоже, не указан в sys.modules - но он действительно работает :)
markm
Однако похоже, что с ipdb это не работает (вставьте в файл «import ipdb; ipdb.set_trace ()»).
gatoatigrado
9
Превосходно! Это просто позволило мне использовать строку документации текущего модуля в качестве сообщения об использовании -sys.modules[__name__].__doc__ .
Джордж
И стать супер-хакером. operators.attrgetter('module.attribute')(sys.modules[__name__])- вы знаете, если вы делаете сумасшедшие вещи, люди говорят вам не делать, например, динамически импортировать пакеты из строк, а затем обезьяна исправляет их, не находясь в классе или что-то в этом
роде
2
Для всех, кто читает комментарий george: sys.modules[__name__].__doc__==, __doc__поскольку он определен в текущем пространстве имен. Поэтому выборка объекта модуля для доступа к его собственным атрибутам не требуется.
Оливер Бестуолтер
1

Может быть, поздно отвечать, но я не нашел для себя правильного ответа. Самое близкое и точное решение (быстрее, чем inspect.stack()) на питоне 3.7.x:

  # search for first module in the stack
  stack_frame = inspect.currentframe()
  while stack_frame:
    print('***', stack_frame.f_code.co_name, stack_frame.f_code.co_filename, stack_frame.f_lineno)
    if stack_frame.f_code.co_name == '<module>':
      if stack_frame.f_code.co_filename != '<stdin>':
        caller_module = inspect.getmodule(stack_frame)
      else:
        # piped or interactive import
        caller_module = sys.modules['__main__']
      if not caller_module is None:
        #... do something here ...
      break
    stack_frame = stack_frame.f_back

Плюсы :

  • Точнее globals()метода.
  • Не зависит от промежуточных кадров стека, которые могут быть добавлены, например, через перехват или с помощью инструментов 3dparty, таких как pytest:
*** foo ... ..
*** boo ... ..
*** runtest c:\python\x86\37\lib\site-packages\xonsh\pytest_plugin.py 58
*** pytest_runtest_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 125
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** <lambda> c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** from_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 229
*** call_runtest_hook c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** call_and_report c:\python\x86\37\lib\site-packages\_pytest\runner.py 176
*** runtestprotocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 95
*** pytest_runtest_protocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 80
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** pytest_runtestloop c:\python\x86\37\lib\site-packages\_pytest\main.py 258
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** _main c:\python\x86\37\lib\site-packages\_pytest\main.py 237
*** wrap_session c:\python\x86\37\lib\site-packages\_pytest\main.py 193
*** pytest_cmdline_main c:\python\x86\37\lib\site-packages\_pytest\main.py 230
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** main c:\python\x86\37\lib\site-packages\_pytest\config\__init__.py 90
*** <module> c:\Python\x86\37\Scripts\pytest.exe\__main__.py 7
  • Может обрабатывать python-канал или интерактивный сеанс.

Минусы:

  • pytest.exeЧто-то вроде очень точного и может возвращать модули, зарегистрированные в исполняемом файле, например, для того, что может не то, что вы хотите.
  • inspect.getmodule все еще может возвращать None на допустимых модулях в зависимости от подключения

У меня есть расширение для Python: как импортировать модуль с полным путем?

Расширение, имеющее функции оболочки для этого случая:

def tkl_get_stack_frame_module_by_offset(skip_stack_frames = 0, use_last_frame_on_out_of_stack = False):
  ...

def tkl_get_stack_frame_module_by_name(name = '<module>'):
  ...

Вам нужно просто правильно инициализировать расширение:

# portable import to the global space
sys.path.append(<path-to-tacklelib-module-directory>)
import tacklelib as tkl

tkl.tkl_init(tkl, global_config = {'log_import_module':os.environ.get('TACKLELIB_LOG_IMPORT_MODULE')})

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

# use `tkl_*` functions directly from here ...
Andry
источник