情况: - 我的project_folder中有一个名为calendar的模块 - 我想使用Python库中的内置Calendar类 - 当我使用日历导入日历时,它会抱怨因为它试图从我的模块加载.
我做了一些搜索,似乎无法找到问题的解决方案.
任何想法,而无需重命名我的模块?
Dam*_*ian 135
无需更改模块的名称.相反,您可以使用absolute_import更改导入行为.例如,使用stem/socket.py,我按如下方式导入套接字模块:
from __future__ import absolute_import
import socket
Run Code Online (Sandbox Code Playgroud)
这仅适用于Python 2.5及更高版本; 它的启用行为是Python 3.0及更高版本中的默认行为.Pylint会抱怨代码,但它完全有效.
Boa*_*niv 36
实际上,解决这个问题相当容易,但实现总是有点脆弱,因为它取决于python导入机制的内部结构,并且它们在未来的版本中会发生变化.
(以下代码显示了如何加载本地和非本地模块以及它们如何共存)
def import_non_local(name, custom_name=None):
import imp, sys
custom_name = custom_name or name
f, pathname, desc = imp.find_module(name, sys.path[1:])
module = imp.load_module(custom_name, f, pathname, desc)
f.close()
return module
# Import non-local module, use a custom name to differentiate it from local
# This name is only used internally for identifying the module. We decide
# the name in the local scope by assigning it to the variable calendar.
calendar = import_non_local('calendar','std_calendar')
# import local module normally, as calendar_local
import calendar as calendar_local
print calendar.Calendar
print calendar_local
Run Code Online (Sandbox Code Playgroud)
如果可能,最佳解决方案是避免使用与标准库或内置模块名称相同的名称命名模块.
Omn*_*ous 14
解决这个问题的唯一方法就是自己劫持内部进口机器.这并不容易,而且充满了危险.你应该不惜一切代价避免使用圣杯形状的灯塔,因为危险太危险了.
重命名您的模块.
如果你想学习如何劫持内部导入机器,你可以在这里找到如何做到这一点:
有时候很有理由陷入这种危险之中.你给出的理由不在其中.重命名您的模块.
如果你采取危险的路径,你将遇到的一个问题是,当你加载一个模块时,它最终会有一个"官方名称",这样Python就可以避免再次解析该模块的内容.可以在中找到模块的"正式名称"到模块对象本身的映射sys.modules
.
这意味着,如果您import calendar
在一个地方,导入的任何模块将被视为具有正式名称的模块,calendar
并且所有其他尝试到import calendar
其他任何地方,包括在主要Python库的其他代码中,将获得该日历.
也许可以使用Python 2.x中的imputil模块设计一个客户导入器,它导致从某些路径加载的模块以非sys.modules
首先或类似的方式查找他们导入的模块.但这是一个非常毛茸茸的事情,无论如何它都无法在Python 3.x中运行.
你可以做一件非常丑陋和可怕的事情,不涉及钩住进口机制.这是你可能不应该做的事情,但它可能会奏效.它将您的calendar
模块转换为系统日历模块和日历模块的混合体.感谢Boaz Yaniv为我使用的功能的骨架.把它放在你calendar.py
文件的开头:
import sys
def copy_in_standard_module_symbols(name, local_module):
import imp
for i in range(0, 100):
random_name = 'random_name_%d' % (i,)
if random_name not in sys.modules:
break
else:
random_name = None
if random_name is None:
raise RuntimeError("Couldn't manufacture an unused module name.")
f, pathname, desc = imp.find_module(name, sys.path[1:])
module = imp.load_module(random_name, f, pathname, desc)
f.close()
del sys.modules[random_name]
for key in module.__dict__:
if not hasattr(local_module, key):
setattr(local_module, key, getattr(module, key))
copy_in_standard_module_symbols('calendar', sys.modules[copy_in_standard_module_symbols.__module__])
Run Code Online (Sandbox Code Playgroud)
已接受的解决方案包含一种现已弃用的方法。
此处的 importlib 文档提供了一个很好的示例,说明了直接从 python >= 3.5 的文件路径加载模块的更合适的方法:
import importlib.util
import sys
# For illustrative purposes.
import tokenize
file_path = tokenize.__file__ # returns "/path/to/tokenize.py"
module_name = tokenize.__name__ # returns "tokenize"
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
Run Code Online (Sandbox Code Playgroud)
因此,您可以从路径加载任何 .py 文件并将模块名称设置为您想要的任何名称。因此,只需将 调整为module_name
您希望模块在导入时具有的任何自定义名称。
要加载包而不是单个文件,file_path
应该是包根目录的路径__init__.py
归档时间: |
|
查看次数: |
47360 次 |
最近记录: |