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?
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.
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.
A module can find out its own module name by looking at the predefined global variable __name__.
__ builtin __ is imported by default on all program run.
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
andlist
withoutfrom builtins import int, list
. So how doint
andlist
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".
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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With