Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find out which module a name is imported from?

Tags:

In a Python program, if a name exists in the namespace of the program, is it possible to find out if the name is imported from some module, and if yes, which module it is imported from?

like image 571
Tim Avatar asked Jun 30 '17 17:06

Tim


People also ask

How can I tell which Python modules are imported?

sys. modules contains all modules used anywhere in the current instance of the interpreter and so shows up if imported in any other Python module. dir() checks whether the name was defined in the current namespace.

How do I identify a Python module?

To make sure Python can always find the module.py , you need to: Place module.py in the folder where the program will execute. Include the folder that contains the module.py in the PYTHONPATH environment variable. Or you can place the module.py in one of the folders included in the PYTHONPATH variable.

How do I find the name of a module?

A module can find out its own module name by looking at the predefined global variable __name__.

Which module is imported by default in Python?

__ builtin __ is imported by default on all program run.


2 Answers

You can see which module a function has been defined in via the __module__ attribute. From the Python Data model documentation on __module__:

The name of the module the function was defined in, or None if unavailable.

Example:

>>> from re import compile
>>> compile.__module__
're'
>>> def foo():
...     pass
... 
>>> foo.__module__
'__main__'
>>>

The Data model later mentions that classes have the same attribute as well:

__module__ is the module name in which the class was defined.

>>> from datetime import datetime
>>> datetime.__module__
'datetime'
>>> class Foo:
...     pass
... 
>>> Foo.__module__
'__main__'
>>> 

You can also do this with builtin names such as int and list. You can accesses them from the builtins module.

>>> int.__module__
'builtins'
>>> list.__module__
'builtins'
>>> 

I can use int and list without from builtins import int, list. So how do int and list become available in my program?

That is because int and list are builtin names. You don't have to explicitly import them for Python to be able to find them in the current namespace. You can see this for yourself in the CPython virtual machine source code. As @user2357112 mentioned, builtin names are accessed when global lookup fails. Here's the relevant snippet:

if (v == NULL) {
    v = PyDict_GetItem(f->f_globals, name);
    Py_XINCREF(v);
    if (v == NULL) {
        if (PyDict_CheckExact(f->f_builtins)) {
            v = PyDict_GetItem(f->f_builtins, name);
            if (v == NULL) {
                format_exc_check_arg(
                            PyExc_NameError,
                            NAME_ERROR_MSG, name);
                goto error;
            }
            Py_INCREF(v);
        }
        else {
            v = PyObject_GetItem(f->f_builtins, name);
            if (v == NULL) {
                if (PyErr_ExceptionMatches(PyExc_KeyError))
                    format_exc_check_arg(
                                PyExc_NameError,
                                NAME_ERROR_MSG, name);
                goto error;
            }
        }
    }
}

In the code above, CPython first searches for a name in the global scope. If that fails, then it falls back and attempts to get the name from a mapping of builtin names in the current frame object its executing. That's what f->f_builtins is.

You can observe this mapping from the Python level using sys._getframe():

>>> import sys
>>> frame = sys._getframe()
>>> 
>>> frame.f_builtins['int']
<class 'int'>
>>> frame.f_builtins['list']
<class 'list'>
>>> 

sys._getframe() returns the frame at the top of the call stack. In this case, its the frame for the module scope. And as you can see from above, the f_builtins mapping for the frame contains both the int and list classes, so Python has automatically made those names available to you. In other words, it's "built" them into the scope; hence the term "builtins".

like image 178
Christian Dean Avatar answered Nov 09 '22 15:11

Christian Dean


If for some reason the source is unavailable, you could use getmodule from inspect which tries its best to find the module by grabbing __module__ if it exists and then falling back to other alternatives.

If everything goes o.k, you get back a module object. From that, you can grab the __name__ to get the actual name of the module:

from inspect import getmodule
from collections import OrderedDict
from math import sin    

getmodule(getmodule).__name__
'inspect'
getmodule(OrderedDict).__name__
'collections'
getmodule(sin).__name__
'math'

If it doesn't find anything, it returns None so you'd have to special case this. In general this encapsulates the logic for you so you don't need to write a function yourself to actually grab __module__ if it exists.

This doesn't work for objects that don't have this information attached. You can, as a fall-back, try and pass in the type to circumvent it:

o = OrderedDict()
getmodule(o)                # None
getmodule(type(0)).__name__ # 'collections'

but that won't always yield the correct result:

from math import pi
getmodule(type(pi)).__name__ 
'builtins'
like image 29
Dimitris Fasarakis Hilliard Avatar answered Nov 09 '22 15:11

Dimitris Fasarakis Hilliard