【问题标题】:When importing my class I lose access to functions from other modules导入我的课程时,我无法访问其他模块的功能
【发布时间】:2015-04-10 23:29:51
【问题描述】:

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

WC_unit 类的方法需要一些 numpy 函数,例如 exp

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

%run WC_class.py

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

导入该类
from classes.WC_class import WC_unit

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

我尝试调用from numpy import *import numpy as np 并将函数调用更改为np.exp(),但我继续收到错误消息。考虑到我有某种范围界定问题或命名空间问题,我已将相同的导入函数放在不同位置,包括test.py 文件、类文件顶部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))

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

  1. 我做错了什么(可能很多,我怀疑)。我认为这与我导入课程的方式有关?但也可能在课程本身中进行范围界定。

  2. 为什么当我 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 上

【问题讨论】:

  • 停止使用from numpy import * 并更喜欢import numpy 并使用numpy.arraynumpy.mean 等。这样可以防止命名空间污染,从而造成您所看到的问题。
  • 请始终为您的问题中的任何错误消息显示完整的回溯

标签: python numpy import scope


【解决方案1】:

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

但是,您不会在 test.py 的顶部执行 from numpy import *,因此当您将 WC_unit 导入脚本时,exp 尚未在当前模块的范围内定义(现在是test 脚本)。

您已经在WC_unit.update() 方法本身中尝试了from numpy import *,但这会失败,因为import * is only allowed at a module level(实际上,当您尝试导入WC_unit 时,您应该看到SyntaxWarning 与此有关!)。由于导入失败,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 *,就没有简单的方法来摆脱你已经导入到你的命名空间的东西(或者恢复你任何旧的模块或变量) '已经通过在它们的顶部导入而崩溃了)。

只要您将每个模块的所有内容保存在其自己单独的命名空间中,就没有命名空间冲突的风险,也不会对每个函数或类的来源产生歧义。按照惯例,我们使用np 来指代numpy 的命名空间,plt 来指代matplotlib.pyplot 等等。

【讨论】:

  • 谢谢!我不确定这是否正是发生的事情,但我肯定能够更多地了解类和对象的工作原理,并将事情分解成更小的块。当我学习如何写作时,我可能会再问一些哲学类型的问题,我很感激你的彻底和直截了当的回答。如果有人可以将我链接到有关如何使用类开发模拟的任何教程,我很乐意阅读它们。特别是我无法弄清楚如何构建我的文件......模块......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 2016-05-29
  • 2021-07-01
  • 1970-01-01
相关资源
最近更新 更多