我正在努力学习如何为运行模拟的科学计算进行面向对象的编码;我正在使用numpy等。我创建了我的第一个类WC_unit
,它位于./classes/WC_class.py
(子目录)。我在__init__.py
目录中创建了一个classes
文件(为空)。
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))
我真的很喜欢我的游戏并弄清楚如何编写我自己的类并使用它们与令人敬畏的计算工具。我想我想知道:
我做错了什么(可能很多,我怀疑)。我认为这与我如何导入课程有关?但也许也在班级本身范围内。
为什么我的班级在import
时会失去对numpy函数的访问权限,但是当我像终端中的脚本一样运行它时却不能访问它?
我想我通常也不明白为什么人们如此保护他们的命名空间,即为什么这么多代码示例显示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上
答案 0 :(得分:1)
当您在IPython中调用%run WC_class.py
时,您正在做的是将该源文件的内容直接加载到交互式命名空间中。因为您已经在IPython会话中调用了from numpy import *
,所以exp
在当前'模块的全局变量集中被定义为numpy.exp
。 (在这种情况下,它只是IPython交互式命名空间),所以当你在exp()
(或WC_unit.update()
内的任何其他地方)中调用WC_class.py
时,它将正常工作。
但是,您没有在from numpy import *
的顶部执行test.py
,因此当您将WC_unit
导入到您的脚本中时exp
尚未定义在test
范围内当前模块(现在是from numpy import *
脚本)。
您已在WC_unit.update()
方法中尝试了SyntaxWarning
,但这会失败,因为import *
is only allowed at a module level(实际上您应该看到WC_unit
你试图导入exp
!)。由于导入失败,WC_unit.update()
仍然未定义,NameError
方法会引发您{1}}。
要做的是在任何使用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 *
后,您将使用exp
覆盖名为numpy.exp
的自己的函数,因此当您稍后调用exp(y)
时,它可能无法执行您期望的操作。例如,这正是一些内置Python函数(如sum
和all
)所发生的情况:
print(sum.__module__)
# __builtin__
from numpy import *
print(sum.__module__)
# numpy.core.fromnumeric
更重要的是,这或多或少是不可逆转的 - 一旦你完成from module import *
,就没有简单的方法可以摆脱你所做的事情。已导入到您的命名空间(或通过导入它们的顶部来恢复任何旧的模块或变量)。
只要将每个模块的所有内容保存在自己独立的命名空间中,就不存在命名空间冲突的风险,也不会对每个函数或类的来源产生歧义。按照惯例,我们使用np
来引用numpy的命名空间,plt
等matplotlib.pyplot
。