我应该通过`from numpy import *`使用numpy(或pylab)作为Python环境吗?

12 投票
5 回答
2594 浏览
提问于 2025-04-16 16:11

我在所有的Python程序中都使用pylab(更具体地说是numpy)。除了极少数例外,我几乎每次都这样做。目前,我已经养成了以以下方式导入numpy的习惯:

from numpy import *

这样做的好处是让numpy看起来就像是Python一开始就有的功能。每个脚本都这样导入numpy,有什么坏处吗?我指的是除了每个脚本/程序会多占一点内存,加载时间会稍长之外。

我觉得每次调用numpy的函数时都要写numpy或者np(比如,np.zeros(3))有点麻烦,因为这需要我知道哪些函数是来自numpy的,哪些不是。我其实并不在乎zeros函数是来自numpy还是Python,我只想用它。

你觉得哪种写法更好呢?

5 个回答

2

我们换个角度来看这个问题。我拿到了你的代码来调试,发现你调用了:

zeros(5)

要检查你的代码里这个是 np.zeros 还是你在别的地方重新定义过,确实挺麻烦的。而且因为 pylab 有930个名字,这种情况很容易发生。

12

为了更详细地说明其他人说的内容,使用 import * 来引入 numpy 模块是个特别糟糕的选择。

pylab 是为了交互式使用而设计的,在这种情况下使用是没问题的。没有人想在命令行里反复输入 pylab.zeros,因为可以直接输入 zeros。但是,一旦你开始写代码,情况就完全不同了。你只需要输入一次,但这段代码可能会一直存在,其他人(比如一年后的你自己)可能会想搞清楚你当时到底在做什么。

除了 @unutbu 提到的关于覆盖 Python 内置的 sumfloatint 等的内容,以及大家提到的关于不知道函数来源的问题,numpypylab 的命名空间都非常大。

numpy 的命名空间里有 566 个函数、变量、类等等。这可真不少!而 pylab 甚至有 930!(而且这些来自很多不同的模块。)

当然,像 zerosonesarray 这样的函数你大概能猜到它们来自哪里,但 sourceDataSourcelib.utils 呢?(如果你使用 from numpy import *,这些都会出现在你的本地命名空间里。)

如果你的项目稍微大一点,很有可能你会有一个本地变量或者其他文件里的变量,名字和 numpy 里的某个东西很相似。突然间,你会更加在意你到底在调用什么!

再举个例子,你怎么区分 pylabfft 函数和 numpyfft 模块 呢?

这取决于你是这样做:

from numpy import *
from pylab import *

还是这样:

from pylab import *
from numpy import *

fft 在这两种情况下是完全不同的东西,行为也完全不同!(也就是说,在第二种情况下调用 fft 会报错。)

总的来说,你应该始终避免使用 from module import *,但在 numpyscipy 等大型模块的情况下,这尤其是个坏主意,因为它们的命名空间太大了。

当然,以上说的都是在前提下,如果你只是想在命令行里快速绘制一些数据的图表,然后再继续做其他事情,那当然可以使用 pylab。这就是它的用途。只要不要用这种方式写出后面的人可能会想看懂的代码就行!

</rant>

19
  1. 使用 from numpy import * 会改变 anyallsum 的行为。举个例子,

    any([[False]])
    # True
    all([[True, False], [False, False]])
    # True
    sum([[1,2],[3,4]], 1) 
    # TypeError: unsupported operand type(s) for +: 'int' and 'list'
    

    而如果你使用 from numpy import *,那么这些值就会完全不同:

    from numpy import *
    any([[False]])
    # False
    all([[True, False], [False, False]])
    # False
    sum([[1,2],[3,4]], 1) 
    array([3, 7])
    

    关于名称冲突的完整列表可以通过这种方式找到(感谢 @Joe Kington 和 @jolvi 提醒这一点):

    import numpy as np
    np_locals = set(np.__all__)
    builtins = set(dir(__builtins__))
    print([name for name in np_locals.intersection(builtins) if not name.startswith('__')])
    # ['any', 'all', 'sum']
    
  2. 这可能会导致非常混乱的错误,因为在没有使用 from numpy import * 的情况下测试或使用你代码的人,可能会看到和你完全不同的行为。

  3. 使用多次 from module import * 的方式会让问题更严重,因为会出现更多这种名称冲突。如果你能及时改掉这个坏习惯,就不必担心这种(可能让人困惑的)错误了。

    如果两个模块都重新定义了同一个名称,导入的顺序也可能会影响结果。

    而且这会让你更难搞清楚函数和变量的来源。

  4. 虽然可以使用 from numpy import * 仍然访问 Python 的内置函数,但这样做会显得很别扭:

    from numpy import *
    any([[False]])
    __builtins__.any([[False]])
    

    而且可读性比下面的方式差:

    import numpy as np
    np.any([[False]])
    any([[False]])
    
  5. 正如 Python 的哲学所说,

    命名空间是个非常好的主意——让我们多用一些吧!

我的建议是,任何脚本中都不要使用 from module import *

撰写回答