什么原因导致ImportError报告“(未知位置)”?

3
看着这个问题, 有这个导入错误:
>>> from flask_security import login_user
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'login_user' from 'flask_security' (unknown location)

什么导致了"(未知位置)"的消息?
在看到这个之前,我有一种模糊的假设,认为它意味着该模块是内置在Python中的,就像sys一样,因此根本没有任何外部文件。
但在链接的问题中显然不是这种情况。
2个回答

3
无法确定的位置在模块的__file__属性未设置(或设置为非字符串)时会出现ImportError
这可能有多种原因:
  1. 与Python解释器静态链接的C模块会使__file__未设置。这包括像问题中提到的sys等模块。
  2. 对于表示命名空间包的模块,__file__将被设置为None
  3. 如果模块是使用types.ModuleType创建的,__file__将不会被设置。
  4. 当使用importlib中的自定义加载器导入模块时,__file__是否被设置取决于加载器的实现。
动态加载的扩展模块会将`__file__`设置为共享库的路径。
以下通过直接使用`types.ModuleType`创建模块会产生一个“(未知位置)”的导入错误。请注意,我们可以在任何时候设置模块的`__file__`属性来改变错误消息的显示方式。
import sys
import types

sys.modules["foo"] = types.ModuleType("foo", "Foo module")

# Import with no __file__ set
>>> from foo import bar
Traceback (most recent call last):
...
ImportError: cannot import name 'bar' from 'foo' (unknown location)

# Set __file__ to a dummy value
>>> sys.modules["foo"].__file__ = "/fake/path/to/foo.py"
>>> from foo import bar
Traceback (most recent call last):
...
ImportError: cannot import name 'bar' from 'foo' (/fake/path/to/foo.py)

同样地,当使用一个不设置模块的__file__属性的自定义加载器时,我们可以看到相同的(未知位置)行为。
import importlib.abc

class SimpleLoader(importlib.abc.Loader):
    def create_module(self, spec):
        return None

    def exec_module(self, module):
        pass


loader = SimpleLoader()
loader.load_module("foo")

>>> from foo import bar
Traceback (most recent call last):
...
ImportError: cannot import name 'bar' from 'foo' (unknown location)

如果自定义加载器将__file__设置为某个值,我们将设置该值,而不是(未知位置)
import importlib.abc


class SpoofLoader(importlib.abc.Loader):
    def create_module(self, spec):
        return None

    def exec_module(self, module):
        module.__file__ = "spoofed location"


loader = SpoofLoader()
loader.load_module("foo")

>>> from foo import bar
Traceback (most recent call last):
...
ImportError: cannot import name 'bar' from 'foo' (spoofed location)

3
最有可能的情况是存在一个PEP 420命名空间包(通常只是一个空文件夹):
$ mkdir example_dir
$ python3 -c 'from example_dir import wat'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: cannot import name 'wat' from 'example_dir' (unknown location)

这几乎肯定是链接问题的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接