python:从外部代码导入 numpy 作为 np 在我自己的用户定义模块中丢失

python: import numpy as np from outer code gets lost within my own user defined module

我正在为科学计算做模拟,我几乎总是想在交互式解释器中四处查看我的模拟输出。我正在尝试编写 classes 来定义模拟对象(神经群体),我想通过在 [=49] 中调用脚本 %run test_class_WC.py 来正式化我对这些 classes 的测试=].由于包含 class 的 module/file 在我尝试调试 it/add 功能时发生变化,因此我每次都重新加载它。

./test_class_WC.py:

import WC_class # make sure WC_class exists
reload(WC_class) # make sure it's the most current version
import numpy as np

from WC_class import WC_unit # put the class into my global namespace?

E1 = WC_unit(Iapp=100)
E1.update() # see if it works
print E1.r

所以我立即使用重新加载来确保我已经加载了最新版本的模块,所以我有最新的 class 定义——我确信这一点笨重得要死(也许更险恶?),但它让我免于做 %run WC_class.py 和不得不单独调用 %run test_WC.py

的麻烦

和./WC_class:

class WC_unit:

    nUnits = 0
    def __init__(self,**kwargs):
        self.__dict__.update(dict(      # a bunch of params
                gee = .6,               # i need to be able to change
                ke=.1,the=.2,           # in test_class_WC.py
                tau=100.,dt=.1,r=0.,Iapp=1.), **kwargs)
        WC_unit.nUnits +=1

    def update(self):
        def f(x,k=self.ke,th=self.the):   # a function i define inside a method
            return 1/(1+np.exp(-(x-th)/k)) # using some of those params
        x = self.Iapp + self.gee * self.r
        self.r += self.dt/self.tau * (-self.r + f(x))

WC_unit 基本上定义了一堆默认参数,并定义了一个使用基本欧拉积分更新的 ODE。我希望 test_class_WC 设置一个包含 np 的全局命名空间(和 WC_unit,以及 WC_class)

当我 运行 它时,出现以下错误:

In [14]: %run test_class_WC.py
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/steeles/Desktop/science/WC_sequence/test_class_WC.py in <module>()
      8 
      9 E1 = WC_unit(Iapp=100)
---> 10 E1.update()
     11 
     12 # if bPlot:

/Users/steeles/Desktop/science/WC_sequence/WC_class.py in update(self)
     19                         return 1/(1+np.exp(-(x-th)/k))
     20                 x = self.Iapp + self.gee * self.r
---> 21                 self.r += self.dt/self.tau * (-self.r + f(x))
     22 
     23         # @class_method

/Users/steeles/Desktop/science/WC_sequence/WC_class.py in f(x, k, th)
     17         def update(self):
     18                 def f(x,k=self.ke,th=self.the):
---> 19                         return 1/(1+np.exp(-(x-th)/k))
     20                 x = self.Iapp + self.gee * self.r
     21                 self.r += self.dt/self.tau * (-self.r + f(x))

NameError: global name 'np' is not defined

现在我可以通过在 WC_class 模块顶部导入 numpy 作为 np 来解决这个问题,或者甚至通过在 test_class_WC 中执行 from numpy import exp 并更改 update() 方法包含 exp() 而不是 np.exp()... 但我不想这样做,因为它很容易,我想了解所有这些 namespace/module 的东西是如何工作的,所以我不再是 python白痴。为什么 np 在 WC_unit 命名空间中迷路了?是因为我在处理两个不同的 files/modules 吗?函数内部对 np.exp 的调用与它有关吗?

我也愿意接受有关改进我的工作流程和文件结构的建议,因为它似乎不是特别 pythonic。如果这有助于任何人理解,我的背景是 MATLAB。我正在 SublimeText2 中编辑我的 .py 文件。抱歉,代码不是很精简,我一直很难重现这个问题。

正确的方法是在子模块的顶部也做一个 import numpy as np。原因如下:

需要注意的关键是在Python中,global实际上意味着"shared at a module-level",并且每个模块的命名空间彼此不同except 当一个模块显式地从另一个模块导入时。一个导入的模块绝对不能访问它的 'parent' 模块的命名空间,从所有方面考虑这可能是一件好事,否则你将拥有其行为完全取决于导入它的模块中定义的变量的模块。

所以当堆栈跟踪显示 global name 'np' is not defined 时,它是在模块级别讨论它。 Python 默认情况下不允许 WC_Class 模块访问其父模块中的对象。

(顺便说一句,effbot 有一个 quick note on how to do inter-module globals

另一个需要注意的关键点是,即使您的代码的各个模块中有多个 import numpy as np,该模块实际上也只会加载(即执行)一次。一旦加载,模块(作为 Python 对象本身)可以在字典 sys.modules 中找到,如果一个模块已经存在于这个字典中,任何 import module_to_import 语句只允许导入模块访问名称在 module_to_import 的命名空间中。因此,将 import numpy as np 分散在代码库中的多个模块中并不浪费。

编辑: 在更深入的挖掘中,effbot 在 Python 3 文档中新增了一个 even deeper (but still pretty quick and simple) exploration of what actually happens in module imports. For deeper exploration of the topic, you may want to check the import system discussion

在Python中导入每个需要的模块是正常的。不要指望任何 'global' 进口。事实上并没有这样的事情。除了一个例外。我在

中发现

Do I have to specify import when Python script is being run in Ipython?

%run -i myscript 在 Ipython 交互式命名空间中运行脚本。所以对于快速测试脚本,这可以节省大量导入。

我认为不需要这种三重导入

import WC_class # make sure WC_class exists
reload(WC_class) # make sure it's the most current version
...
from WC_class import WC_unit

如果您全部使用 WC_class 中的内容,只需使用最后一行。