假设您在一个名为 logging.py 的文件中。如果您尝试导入标准日志记录模块,您最终会导入您所在的文件。如何从这里导入标准日志记录模块?
4 回答
您总是可以从 中删除当前目录sys.path
,但这是非常骇人听闻的,而且不可靠。经过测试,我意识到如果文件正在运行,这可以工作(作为__main__
,但如果它正在被导入,这是非常不可靠的)。
我认为你能做的最好的事情就是不要用 std lib 包使用的名称来命名你的文件。
那么您可以使用imp
绝对路径加载模块。
import imp
help(imp.load_module)
load_module(...)
load_module(name, file, filename, (suffix, mode, type)) -> module
Load a module, given information returned by find_module().
The module name must include the full package name, if any.
在我的 Mac 上,我这样做了:
import imp
py_logging = imp.load_module('logging', None, '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging', ('', '', 5))
dir(py_logging)
['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'FATAL', 'FileHandler', 'Filter', 'Filterer', 'Formatter', 'Handler', 'INFO', 'LogRecord', 'Logger', 'LoggerAdapter', 'Manager', 'NOTSET', 'PlaceHolder', 'RootLogger', 'StreamHandler', 'WARN', 'WARNING', '__all__', '__author__', '__builtins__', '__date__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__status__', '__version__', '_acquireLock', '_defaultFormatter', '_handlerList', '_handlers', '_levelNames', '_lock', '_loggerClass', '_releaseLock', '_srcfile', '_startTime', 'addLevelName', 'atexit', 'basicConfig', 'cStringIO', 'codecs', 'critical', 'currentframe', 'debug', 'disable', 'error', 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'info', 'log', 'logProcesses', 'logThreads', 'makeLogRecord', 'os', 'raiseExceptions', 'root', 'setLoggerClass', 'shutdown', 'string', 'sys', 'thread', 'threading', 'time', 'traceback', 'types', 'warn', 'warning']
dir(logging)
['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'FATAL', 'FileHandler', 'Filter', 'Filterer', 'Formatter', 'Handler', 'INFO', 'LogRecord', 'Logger', 'LoggerAdapter', 'Manager', 'NOTSET', 'PlaceHolder', 'RootLogger', 'StreamHandler', 'WARN', 'WARNING', '__all__', '__author__', '__builtins__', '__date__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__status__', '__version__', '_acquireLock', '_defaultFormatter', '_handlerList', '_handlers', '_levelNames', '_lock', '_loggerClass', '_releaseLock', '_srcfile', '_startTime', 'addLevelName', 'atexit', 'basicConfig', 'cStringIO', 'codecs', 'critical', 'currentframe', 'debug', 'disable', 'error', 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'info', 'log', 'logProcesses', 'logThreads', 'makeLogRecord', 'os', 'raiseExceptions', 'root', 'setLoggerClass', 'shutdown', 'string', 'sys', 'thread', 'threading', 'time', 'traceback', 'types', 'warn', 'warning']
正如我们所看到的,我们拥有相同的组件集。
请记住,这不是很干,这意味着您需要根据您所在的底层系统更新日志模块的位置,您可以通过以下方式检查它
>>> import logging
>>> logging.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.pyc'
或在找不到imp.find_module
fp, pathname, description = imp.find_module('logging')
您的自定义的目录中使用...logging.py
作为最后一点,我确定你有理由命名你的模块logging.py
,我仍然会推荐其他不会冲突的东西。
来自 samy.vilar 的答案提供了许多有用的选项。但是,如果您正在寻找最简单、最直接的答案:
import imp
import sys
f, pathname, desc = imp.find_module('logging', sys.path[1:])
logging = imp.load_module('logging', f, pathname, desc)
这里有几点需要注意:
该load_module
调用更像reload(logging)
是import logging
它不会logging
在本地范围内绑定名称,而是会替换名称下的任何现有模块logging
。所以,如果你在此之前做过一个import logging
,那么这个名字现在指的是新模块,而不是旧模块;如果没有,则名称logging
不会绑定在您的范围内。(这就是为什么在logging =
上面,将其纳入范围。)
我不知道是否真的保证将当前目录放入模块路径的''实际上是sys.path
. 就此而言,始终可以自己将“”或“.”插入到 sys.path 中。所以,如果你想变得偏执,你可以这样做:
f, pathname, desc = imp.find_module('logging', [path for path in sys.path if path and path[0] != '.'])
或者您可能会变得更加偏执,例如,比较并abspath(path)
以各种方式确保没有人偷偷地强迫您重新导入自己。这取决于你的目标是什么。sys.argv[0]
os.getcwd()
导入的文件缓存在 中sys.modules
,任何尝试导入另一个同名模块的尝试都只会返回缓存的模块。没有办法解决冲突。
作为一个黑客,你可以删除 中的字典条目sys.modules
,但我不知道这会有多好。买者自负。
del sys.modules['logging']
当然,在那之后,您必须找到一种方法来修改路径,以便导入正确的文件。
我的总体建议是完全防止这种情况并重命名您的文件,以免发生冲突。