157

What I'm trying to do would look like this in the command line:

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

How can I get a reference to all the names defined in mymodule from within mymodule itself?

Something like this:

# mymodule.py
names = dir(__thismodule__)
guillermooo
  • 7,915
  • 15
  • 55
  • 58
  • please also check https://stackoverflow.com/questions/3281300/automatically-call-all-functions-matching-a-certain-pattern-in-python – ksridhar Aug 07 '18 at 11:45

3 Answers3

209

As previously mentioned, globals gives you a dictionary as opposed to dir() which gives you a list of the names defined in the module. The way I typically see this done is like this:

import sys
dir(sys.modules[__name__])
jamesls
  • 5,428
  • 1
  • 28
  • 17
  • 2
    I was going to add a comment that this wouldn't work for the '__main__' module (which is what the module run at the terminal is called) because that does not seem to be listed in sys.modules - but it does indeed work :) – markm Jul 28 '11 at 01:07
  • However, it doesn't seem to work from ipdb (insert "import ipdb; ipdb.set_trace()" into your file). – gatoatigrado Jun 20 '12 at 22:04
  • 12
    Excellent! This just allowed me to use the current module's docstring as a usage message - `sys.modules[__name__].__doc__`. – george Aug 01 '13 at 07:59
  • And to get super hacky. `operators.attrgetter('module.attribute')(sys.modules[__name__])` -- you know, if you do crazy things people tell you not to do like dynamically import packages from strings and then monkey patch those while not being within a class or anything... – casey Mar 24 '16 at 00:47
  • "Excellent! This just allowed me to use..." `sys.modules[__name__].get_config = lambda: config` in my module's `init()` function to freeze the results once config changes (which are just global vars) have no meaning. I use this in my log_lib that has been improving for nearly 10 years. – Bruno Bronosky Dec 28 '16 at 00:19
  • 5
    For anyone reading comment by george: `sys.modules[__name__].__doc__` == `__doc__` as this is defined in the current namespace. Fetching the module object to access its own attributes is therefore not necessary. – Oliver Bestwalter Aug 04 '19 at 11:07
163

Just use globals()

globals() — Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).

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

Maciej Pasternacki
  • 2,830
  • 2
  • 20
  • 14
  • 7
    Is there any way to access the gloabals() of the calling module, instead of the defining module? – dimo414 Jul 22 '12 at 07:02
  • 10
    You may try getting caller's globals from the traceback module (http://docs.python.org/library/traceback.html), but this is getting into dark magic territory. I don't know what you're trying to do, but you may want to rethink your design if you need that. – Maciej Pasternacki Jul 24 '12 at 14:37
  • A classic case of "I need X (to get Y done) -> You don't need X you need Z". I do need X though! No offense, I just find this amusing, and the most voted answer gives me the answer I need :) – pawamoy Sep 14 '19 at 15:27
  • 1
    Important to note that the globals() can return wrong result as it depends on the context where being called. For example, if make a call from a class function, then it will return the global context linked to the class, not the current module context, which is significally different thing. Even if make a call from a free function it can return a different module global context, dependent on how the function has been imported. – Andry Nov 02 '19 at 15:27
6

It might be late to answer, but I didn't found the correct answer for myself. The most closest and precise solution (faster than inspect.stack()) in the python 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

Pros:

  • Preciser than globals() method.
  • Does not depend on the stack intermediate frames, which can be added for example, via hooking or by the 3dparty tools like 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
  • Can handle python piped or interactive session.

Cons:

  • A kind of much precise and can return modules registered in an executable like for the pytest.exe which might not what you want.
  • inspect.getmodule still may return None on valid modules depending on hooking

I have an extension to the python: How to import a module given the full path?

The extension having wrapper functions for that case:

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>'):
  ...

You have to just initialize the extension properly:

# 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 ...
Shudipta Sharma
  • 5,178
  • 3
  • 19
  • 33
Andry
  • 2,273
  • 29
  • 28