加载numpy时,本地脚本与内置模块冲突

She*_*ohn 6 python numpy anaconda conda

有很多关于相对/绝对导入问题的帖子,其中大部分都是关于Python 2和/或导入子模块的.这不是我的情况:

  • 我使用的是Python 3,所以绝对导入是默认的;
  • (我也用Python 2重现了这个问题);
  • 我不是试图从另一个子模块或任何其他复杂的情况导入子模块.我只想尝试import numpy一个脚本.

我的问题很简单:

.
??? foo
    ??? a.py
    ??? math.py

1 directory, 2 files
Run Code Online (Sandbox Code Playgroud)

其中a.py只包含import nupmymath.py包含x++(故意无效).

在这种情况下,python3 foo/a.py由于NumPy似乎无法导入标准math模块,因此运行会导致错误:

Traceback (most recent call last):
  File "foo/a.py", line 1, in <module>
    import numpy
  File "/path/to/Anaconda3/lib/python3.6/site-packages/numpy/__init__.py", line 158, in <module>
    from . import add_newdocs
  File "/path/to/Anaconda3/lib/python3.6/site-packages/numpy/add_newdocs.py", line 13, in <module>
    from numpy.lib import add_newdoc
  File "/path/to/Anaconda3/lib/python3.6/site-packages/numpy/lib/__init__.py", line 3, in <module>
    import math
  File "/private/tmp/test-import/foo/math.py", line 1
    x++
      ^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)

我对Python相对缺乏经验,但这看起来像是一个bug.我认为import mathPython 3中的语句表现为绝对导入; 本地文件如何与标准模块冲突?难道我做错了什么?

为了澄清,我发现令人惊讶的是NumPy无法加载标准数学模块import math,因为我的本地文件夹中有一个名为的文件math.py.请注意,我从不尝试自己导入该模块.


编辑

这似乎是一个特定的问题conda(与Anaconda和Miniconda一起复制).我正在使用Anaconda 5.2.0(在OSX 10.13.6上),评论中的人已经能够使用不同版本的python/anaconda和不同的系统进行复制.

我能够通过以下方式重现此问题:

  • Anaconda3 v5.2.0,在一个conda环境中使用python 3.4,3.5,3.6和3.7 ,或者只是使用默认的二进制文件(即/path/to/anaconda3/bin).
  • Miniconda2和Miniconda3(numpy需要手动安装),再次在conda环境内部或外部.
  • 一个干净的Homebrew安装brew install python.

在所有情况下,看起来内置模块可能不完整:

> python3 -c "import sys; print(sys.builtin_module_names)"
('_ast', '_codecs', '_collections', '_functools', '_imp', '_io', '_locale', '_operator', '_signal', '_sre', '_stat', '_string', '_symtable', '_thread', '_tracemalloc', '_warnings', '_weakref', 'atexit', 'builtins', 'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'posix', 'pwd', 'sys', 'time', 'xxsubtype', 'zipimport')

> python2 -c "import sys; print sys.builtin_module_names"
('__builtin__', '__main__', '_ast', '_codecs', '_sre', '_symtable', '_warnings', '_weakref', 'errno', 'exceptions', 'gc', 'imp', 'marshal', 'posix', 'pwd', 'signal', 'sys', 'thread', 'xxsubtype', 'zipimport')
Run Code Online (Sandbox Code Playgroud)

重现这个问题

确保你有一个可以导入numpy的Python版本.打开终端并输入:

D=$(mktemp -d)                      # temporary folder
pushd "$D"                          # move there 
mkdir foo                           # create subfolder
echo 'import numpy' >| foo/a.py     #   script a.py
echo 'x++' >| foo/math.py           #   script math.py (invalid)
python foo/a.py                     # run a.py
popd                                # leave temp folder
Run Code Online (Sandbox Code Playgroud)

use*_*ica 0

“绝对导入”并不意味着“标准库导入”。这意味着import math总是尝试导入math模块,而不是currentpackage.math如果导入发生在包内则首先尝试的旧行为。这并不意味着sys.pathPython在确定模块位置时会跳过非 stdlib 条目math。在你的情况下,根据Python导入系统的规则,你的math.py就是math模块。


您通过该行找到的教程链接

当导入名为 spam 的模块时,解释器首先搜索具有该名称的内置模块。

指的是直接编译成Python可执行文件的模块,例如sys. 这些模块built-in在他们的repr

>>> sys
<module 'sys' (built-in)>
Run Code Online (Sandbox Code Playgroud)

您可以在 中看到所有此类模块的名称sys.builtin_module_names。对我来说,这些名字是

>>> sys.builtin_module_names
('_ast', '_codecs', '_collections', '_functools', '_imp', '_io', '_locale', '_operator', '_signal', '_sre', '_stat', '_string', '_symtable', '_thread', '_tracemalloc', '_warnings', '_weakref', 'atexit', 'builtins', 'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'posix', 'pwd', 'sys', 'time', 'xxsubtype', 'zipimport')
Run Code Online (Sandbox Code Playgroud)

math从这个意义上说,它不是内置的。