Як отримати посилання на атрибути поточного модуля в Python


119

Що я намагаюся зробити, виглядатиме так у командному рядку:

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

Як я можу отримати посилання на всі імена, визначені mymoduleвсередині mymoduleсебе?

Щось на зразок цього:

# mymodule.py
names = dir(__thismodule__)

Будь ласка, перевірте stackoverflow.com/questions/3281300 / ...
ksridhar

Відповіді:


135

Просто використовуйте глобалі ()

globals () - Повернення словника, що представляє поточну таблицю глобальних символів. Це завжди словник поточного модуля (всередині функції або методу, це модуль, де він визначений, а не модуль, з якого він викликається).

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


4
Чи є якийсь спосіб отримати доступ до gloabals () викличного модуля замість визначального модуля?
dimo414

9
Ви можете спробувати отримати глобальний номер абонента з модуля traceback ( docs.python.org/library/traceback.html ), але це потрапляє на територію темної магії. Я не знаю, що ви намагаєтеся зробити, але ви, можливо, захочете переосмислити свій дизайн.
Мацей Пастернацький

Класичний випадок "Мені потрібен X (щоб завершити Y) -> Вам не потрібен X, потрібен Z". Мені все-таки потрібно X! Без образи, я просто вважаю це кумедним, і найбільш голосована відповідь дає мені потрібну мені відповідь :)
pawamoy

Важливо зазначити, що глобалі () можуть повернути неправильний результат, оскільки це залежить від контексту, де викликається. Наприклад, якщо здійснити виклик з класової функції, то він поверне глобальний контекст, пов'язаний з класом, а не поточний контекст модуля, що суттєво відрізняється. Навіть якщо здійснити виклик від вільної функції, він може повернути інший модульний глобальний контекст, залежно від способу імпорту.
Андрій

163

Як вже було сказано раніше, глобалі надає словник на відміну від dir (), який дає вам список імен, визначених у модулі. Я зазвичай бачу це зроблено так:

import sys
dir(sys.modules[__name__])

2
Я збирався додати коментар, що це не буде працювати для " головного " модуля (так називається модуль, що працює в терміналі), оскільки це, схоже, не вказано в sys.modules - але це дійсно працює :)
markm

Однак, схоже, це не працює з ipdb (вставте "імпорт ipdb; ipdb.set_trace ()" у ваш файл).
gatoatigrado

9
Відмінно! Це просто дозволило мені використовувати доктрину поточного модуля як повідомлення про використання - sys.modules[__name__].__doc__.
Джордж

І отримати супер хакі. operators.attrgetter('module.attribute')(sys.modules[__name__])- ви знаєте, якщо ви робите божевільні речі, люди говорять вам не робити динамічно імпортувати пакунки з рядків, а потім мавпа виправляти їх, не перебуваючи в класі чи що-небудь ...
casey

2
Для всіх, хто читає коментар від george: sys.modules[__name__].__doc__== __doc__оскільки це визначено в поточному просторі імен. Тому отримання об'єкта модуля для доступу до його власних атрибутів не є необхідним.
Oliver Bestwalter

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
  • Може обробляти пітфонні або інтерактивні сеанси.

Мінуси:

  • Різновиди, які є дуже точними і можуть повертати модулі, зареєстровані у виконуваному файлі, на зразок 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 ...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.