【问题标题】:When can import find a module when nothing else can?什么时候可以 import 找到一个模块,而其他什么都找不到?
【发布时间】:2016-08-12 07:34:32
【问题描述】:

简而言之,这怎么会发生?

cternus@astarael:~⟫ python
Python 2.7.12 (default, Jun 29 2016, 14:05:02)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import backports
>>> import imp
>>> imp.find_module('backports')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named backports

imp 模块声称是“用于实现导入语句的机制的接口”。如果是这样,为什么import 语句可以找到backports,而imp.find_module() 却找不到?

对于某些背景:backports 声称是“命名空间包”,而不是本身的包;其他模块,例如backports.shutil_get_terminal_size,位于此命名空间中。这构成了an ultimately-rejected PEP 的基础。我问这个问题是因为我有 this issue 的变体,并且正在尝试追查原因。

更多怪异:

>>> backports.__file__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute '__file__'
>>> dir(backports)
['__doc__', '__name__', '__path__']
>>> backports.__path__
['/Library/Python/2.7/site-packages/backports']
>>> import os; os.path.exists(backports.__path__[0])
False

(不,我的系统上没有名为 backportsbackports.py 的文件或目录。)

编辑澄清:我知道这可能代表我系统的一种奇怪的配置状态。我的问题不是“我该如何解决这个问题”,而是“这怎么可能?”

【问题讨论】:

  • 可能应该是“我的 Python 环境有什么特别之处?”,因为我得到了 backports.__file__ == '.../lib/python2.7/site-packages/backports/__init__.pyc' 足够好。你是如何安装 backports 的?
  • 出于好奇,在执行import backports 之前尝试检查"backports" in sys.modules,如果已经加载,请尝试在del sys.modules["backports"] 之后导入
  • @TadhgMcDonald-Jensen 'backports': &lt;module 'backports' (built-in)&gt; Huuuuuhhhh

标签: python python-2.7


【解决方案1】:

这个模块可以通过python-configparserAPT包自带。

这怎么可能?

这是可能的,因为python-configparser 使用路径配置文件.pth 文件):

root@ubuntu18.10:/# dpkg -L python-configparser | head | tail -n 1
/usr/lib/python2.7/dist-packages/configparser-3.5.0b2-nspkg.pth

这个文件在解释器启动时由 python 的 site 模块自动拾取,因为它位于/usr/lib/python2.7/dist-packages/ 并具有.pth 扩展名。作为docs say

路径配置文件是名称格式为 name.pth 且存在于上述四个目录之一中的文件... 执行以 import 开头的行(后跟空格或制表符)。

文件/usr/lib/python2.7/dist-packages/configparser-3.5.0b2-nspkg.pth 包含以下内容:

import sys, types, os;has_mfs = sys.version_info > (3, 5);p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('backports', ));importlib = has_mfs 和 __import__('importlib.util');has_mfs 和 __import__('importlib.machinery');m = has_mfs 和 sys.modules.setdefault('backports', importlib.util.module_from_spec(importlib.machinery .PathFinder.find_spec('backports', [os.path.dirname(p)])));m = m 或 sys.modules.setdefault('backports', types.ModuleType('backports'));mp = ( m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)

因此,此代码在 python 启动时自动执行。稍微美化一下,看起来是这样的:

import sys, types, os

has_mfs = sys.version_info > (3, 5)

p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('backports',))
importlib = has_mfs and __import__('importlib.util')
has_mfs and __import__('importlib.machinery')

m = has_mfs and sys.modules.setdefault('backports', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('backports', [os.path.dirname(p)])))

m = m or sys.modules.setdefault('backports', types.ModuleType('backports'))

mp = (m or []) and m.__dict__.setdefault('__path__',[])

(p not in mp) and mp.append(p)

它的作用(至少在 python 2 上)是:它手动通过调用 types.ModuleType 构造函数创建一个模块对象(这就是它看起来像 &lt;module 'backports' (built-in)&gt; 的原因)并将其放入 @987654332 @ 和sys.modules.setdefault('backports', types.ModuleType('backports'))。将其添加到 sys.modules 后,import backports 将只返回该对象。

__path__ 给出提示

root@ubuntu18.10:/# python -c 'import backports; print backports.__path__'
['/usr/lib/python2.7/dist-packages/backports']
root@ubuntu18.10:/# dpkg -S /usr/lib/python2.7/dist-packages/backports
python-configparser: /usr/lib/python2.7/dist-packages/backports

我没有名为 backports 的文件或目录

在 Ubuntu 上,有 /usr/lib/python2.7/dist-packages/backports 由这个包带来如上图,所以我不知道你为什么没有它。也许它是另一个行为相似的包/它的变体对于 MacOS 是不同的/您只是在调试问题时删除了该目录?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多