导入我的 class 时,我无法访问其他模块的功能

When importing my class I lose access to functions from other modules

我正在尝试学习如何为科学计算进行面向对象的编码运行进行模拟;我正在使用 numpy 等。我创建了我的第一个 class、WC_unit,它位于 ./classes/WC_class.py(一个子目录)。我在 classes 目录中创建了一个 __init__.py 文件(它是空的)。

WC_unit class 的方法需要一些 numpy 函数,比如 exp

当我 运行 来自终端的代码(在 ipython 中)时,使用

%run WC_class.py

我可以生成 class E1 = WC_unit() 的一个实例,我可以 运行 它上面的相关方法,即 E1.update() 我真的不知道它是否有效。我在位于的脚本 test.py 中编写了一些外部代码。 (在 ./classes 之上)测试我正在生成的对象,我正在尝试使用

导入 class
from classes.WC_class import WC_unit

现在,当我创建 class 和 运行 E1.update() 的实例 E1 时,我收到错误消息 global name 'exp' is not defined.

我试过调用 from numpy import *import numpy as np 并将函数调用更改为 np.exp(),但我仍然遇到错误。考虑到我遇到了某种范围界定问题或命名空间问题,我将相同的导入函数放在不同的位置,包括 test.py 文件、class 文件的顶部 WC_class.py ,甚至在方法中:

class WC_unit:
    def __init__(self): [assign default pars from a dict including r, dt, tau, and Iapp]...
    def update(self):
        from numpy import *
        self.r += self.dt/self.tau * (-self.r + exp(self.Iapp))

我真的很想提高我的水平,弄清楚如何编写我自己的 classes 并将它们与很棒的计算工具一起使用。我想我想知道:

  1. 我做错了什么(我怀疑可能很多)。我认为这与我导入 class 的方式有关?但也许也在 class 本身范围内。

  2. 为什么我的 class 在我 import 时无法访问 numpy 函数,但在我 运行 它就像终端中的脚本一样?

  3. 我想我通常也不明白为什么人们如此保护他们的命名空间,即为什么这么多代码示例显示 import numpy as np 并将所有函数用作 np.exp(x), 等等。我没有太多的计算机科学背景,所以我可以从你提供的任何解释中受益匪浅——文档对我来说有点神秘。

Python 版本:2.7.8 |Anaconda 2.1.0 (x86_64)| (默认,2014 年 8 月 21 日,15:21:46) [GCC 4.2.1 (Apple Inc. build 5577)] 在 Mac OSX 10.6.8

当您在 IPython 中调用 %run WC_class.py 时,您正在做的是将该源文件的内容直接加载到交互式命名空间中。因为您已经在 IPython 会话中调用了 from numpy import *,所以 exp 在当前 'module' 的全局变量集中被定义为 numpy.exp(其中,在在这种情况下,只是 IPython 交互式命名空间),因此当您在 WC_unit.update() 中调用 exp()(或 WC_class.py 中的任何其他地方)时,它将正常工作。

但是,你没有在test.py的顶部做一个from numpy import *,因此当你将WC_unit导入你的脚本时,exp还没有被定义在当前模块的范围(现在是 test 脚本)。

您已经在 WC_unit.update() 方法本身中尝试了 from numpy import *,但这会失败,因为 import * is only allowed at a module level(事实上,您应该已经看到 SyntaxWarning你试图导入 WC_unit!)。由于导入失败,exp 仍未定义,WC_unit.update() 方法将引发您看到的 NameError

应该做的是在任何使用 numpy 函数的源文件的顶部有一个导入行:

import numpy as np

然后通过 np. 命名空间引用任何 numpy 函数。


关于你的第三点,这样做的主要原因

import numpy as np

x = np.exp(y) # etc.

而不是

from numpy import *

x = exp(y)   # etc.

是后一种方法污染了你的全局命名空间。

假设您已经定义了自己的函数 exp。当您执行 from numpy import * 时,您将用 numpy.exp 覆盖您自己的名为 exp 的函数,因此当您稍后调用 exp(y) 时,它可能不会执行您期望的操作。例如,这正是某些内置 Python 函数(例如 sumall:

所发生的情况
print(sum.__module__)
# __builtin__

from numpy import *

print(sum.__module__)
# numpy.core.fromnumeric

此外,这或多或少是不可逆的 - 一旦您完成了 from module import * 就没有简单的方法来摆脱您导入到命名空间的东西(或恢复任何旧的您通过在其顶部导入而破坏的模块或变量)。

只要您将每个模块的所有内容保存在其自己单独的命名空间中,就没有命名空间冲突的风险,并且每个函数或 class 的来源也不会含糊不清。按照惯例,我们使用 np 来引用 numpy 的命名空间,plt 用于 matplotlib.pyplot