在 Python 中覆盖命名空间

Posted

技术标签:

【中文标题】在 Python 中覆盖命名空间【英文标题】:Override namespace in Python 【发布时间】:2010-11-08 22:25:09 【问题描述】:

假设有一个文件夹“/home/user/temp/a40bd22344”。该名称是完全随机的,并且在每次迭代中都会发生变化。我需要能够使用固定名称在 Python 中导入此文件夹,例如“项目”。我知道我可以将此文件夹添加到 sys.path 以启用导入查找,但有没有办法将 'a40bd22344' 替换为 'project'?

也许在 init.py 中有一些巧妙的技巧?

添加:

它需要是全局的——即其他脚本通过标准加载“项目”:

import project

必须正常工作,改为加载a40bd22344。

【问题讨论】:

为什么不能修复创建临时文件的进程?在源头上解决这个问题会更容易,而不是创建一个复杂的解决方法。将 /temp/ 中的名称固定为真正的模块名称有什么问题? 我无法控制,文件夹是由 CI 服务器创建的。 【参考方案1】:

这是一种方法,无需触及 sys.path,使用 Python 中的 imp 模块:

import imp

f, filename, desc = imp.find_module('a40bd22344', ['/home/user/temp/'])
project = imp.load_module('a40bd22344', f, filename, desc)

project.some_func()

这里是关于imp 模块的一些优秀文档的链接:

imp — Access the import internals

【讨论】:

这不会触及 sys.path 但我认为使用 imp 会导致每次执行此代码时重新加载包。我更喜欢 Alex 的解决方案,因为即使执行多次,它也会做正确的事情。【参考方案2】:

您首先使用 import 导入它:

>>> __import__('temp/a40bd22344')
<module 'temp/a40bd22344' from 'temp/a40bd22344/__init__.py'>

然后你确保这个模块被 Python 知道为project

>>> import sys
>>> sys.modules['project'] = sys.modules.pop('temp/a40bd22344')

在此之后,当前 Python 会话中的任何导入项目都将获得原始模块

>>> import project
>>> project
<module 'temp/a40bd22344' from 'temp/a40bd22344/__init__.py'>

这也适用于子模块:如果您在同一位置有一个 foobar.py,您将获得

>>> import project.foobar
>>> project.foobar
<module 'project.foobar' from 'temp/a40bd22344/foobar.py'>

附录。这是我正在运行的内容:

>>> print sys.version
2.5.2 (r252:60911, Jul 31 2008, 17:28:52) 
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)]

【讨论】:

非常好,除了它不起作用的小细节:在 Python 2.6 和 3.1 中,它说“ImportError:不支持按文件名导入。”,在 2.5 中只是“ImportError:没有名为 temp 的模块/a40bd22344",在 import 上(刚刚在我的 Mac 上尝试了所有三个,以确认我没有忘记 import 的工作原理!-)。我认为它可以在您的平台 krawyoti 和您的 Art 上运行,否则您不会将其标记为已接受,所以我很好奇:这些平台是什么? 好吧,我使用的 import 中的这个漏洞已经修复。我也懒得在 Python 2.6 中尝试它。 亚历克斯,为我工作。 Ubuntu/python 2.5/2.6。您需要在 import 中使用完整路径,或者将其添加到 sys.path,然后仅在文件夹名称上调用 import 您可能还想设置模块的__name__ 属性,以便检查它的代码将其视为与查看sys.modules 的代码相同。【参考方案3】:

当然,正确设置sys.path 后的project = __import__('a40bd22344') 将正常工作。

假设您想在一个函数中执行此操作,将完整路径作为参数并正确设置 projectglobal 导入(以及神奇地使 import project 之后在其他模块中工作)。小菜一碟:

def weirdimport(fullpath):
  global project

  import os
  import sys
  sys.path.append(os.path.dirname(fullpath))
  try:
      project = __import__(os.path.basename(fullpath))
      sys.modules['project'] = project
  finally:
      del sys.path[-1]

这也让 sys.path 保持原样。

【讨论】:

我刚刚对我的问题进行了澄清,在这种情况下也可以吗? Alex,把import语句放在try..finally括号里,保证sys.path总是正确恢复。 @Art,正如@krawyoti 所说,正如@krawyoti 所说,这是通过将其粘贴在 sys.modules[project] 中来完成的。 @krawyoti,好建议——让我编辑以反映这两个变化。

以上是关于在 Python 中覆盖命名空间的主要内容,如果未能解决你的问题,请参考以下文章

覆盖 gSOAP 中的命名空间

覆盖在命名空间中导入的函数

MessageBodyMember 命名空间覆盖 WSDL 中的 DataContract 命名空间

如何覆盖包命名空间中的不可见函数?

python命名空间和作用域

R:临时覆盖函数和范围/命名空间