简体   繁体   中英

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

在 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 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" .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM