在 Python 程序中,如果名称存在于程序的命名空间中,是否可以找出该名称是否从某个模块导入,如果是,它是从哪个模块导入的?
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 ok, 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'
一些对象(但远非全部)具有属性__module__ 。
Unless code is doing something unusual like updating globals directly, the source code should indicate where every variable came from:
x = 10 # Assigned in the current module
from random import randrange # Loaded from random
from functools import * # Loads everything listed in functools.__all__
You can also look at globals()
, it will output a dict with all the names python uses BUT also the variable, modules and functions you declared inside the namespace.
>>> x = 10
>>> import os
>>> globals() # to big to display here but finish with
# {... 'x': 10, 'os': <module 'os' from '/usr/local/lib/python2.7/os.py'>}
Therefore, you can test if variable were declared like this:
if globals()['x']:
print('x exist')
try:
print(globals()['y'])
except KeyError:
print('but y does not')
# x exist
# but y does not
Works also with modules:
print(globals()['os']) # <module 'os' from '/usr/local/lib/python2.7/os.py'>
try:
print(globals()['math'])
except KeyError:
print('but math is not imported')
# <module 'os' from '/usr/local/lib/python2.7/os.py'>
# but math is not imported
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.