3

I'm doing simulations for scientific computing, and I'm almost always going to want to be in the interactive interpreter to poke around at the output of my simulations. I'm trying to write classes to define simulated objects (neural populations) and I'd like to formalize my testing of these classes by calling a script %run test_class_WC.py in ipython. Since the module/file containing the class is changing as I try to debug it/add features, I'm reloading it each time.

./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

So right off the bat I'm using reload to make sure I've got the most current version of the module loaded so I've got the freshest class definition-- I'm sure this is clunky as heck (and maybe more sinister?), but it saves me some trouble from doing %run WC_class.py and having to do a separate call to %run test_WC.py

and ./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 basically defines a bunch of default parameters and defines an ODE that updates using basic Euler integration. I expect that test_class_WC sets up a global namespace containing np (and WC_unit, and WC_class)

When I run it, I get the following error:

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

Now I can get around this by just importing numpy as np in top of the WC_class module, or even by doing from numpy import exp in test_class_WC and change the update() method to contain exp() instead of np.exp()... but I'm not trying to do this because it's easy, I want to learn how all this namespace/module stuff works so I stop being a python idiot. Why is np getting lost in the WC_unit namespace? Is it because I'm dealing with two different files/modules? Does the call to np.exp inside a function have to do with it?

I'm also open to suggestions regarding improving my workflow and file structure, as it seems to be not particularly pythonic. My background is in MATLAB if that helps anyone understand. I'm editing my .py files in SublimeText2. Sorry the code is not very minimal, I've been having a hard time reproducing the problem.

1
  • You need to import numpy as np at the top of WC_class.py Commented Feb 11, 2015 at 2:15

2 Answers 2

4

The correct approach is to do an import numpy as np at the top of your sub-module as well. Here's why:

The key thing to note is that in Python, global actually means "shared at a module-level", and the namespaces for each module exist distinct from each other except when a module explicitly imports from another module. An imported module definitely cannot reach out to its 'parent' module's namespace, which is probably a good thing all things considered, otherwise you'll have modules whose behavior depends entirely on the variables defined in the module that imports it.

So when the stack trace says global name 'np' is not defined, it's talking about it at a module level. Python does not let the WC_Class module access objects in its parent module by default.

(As an aside, effbot has a quick note on how to do inter-module globals)

Another key thing to note is that even if you have multiple import numpy as np in various modules of your code, the module actually only gets loaded (i.e. executed) once. Once loaded, modules (being Python objects themselves) can be found in the dictionary sys.modules, and if a module already exists in this dictionary, any import module_to_import statement simply lets the importing module access names in the namespace of module_to_import. So having import numpy as np scattered across multiple modules in your codebase isn't wasteful.

Edit: On deeper digging, effbot has an 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 newly added in the Python 3 documentation.

Sign up to request clarification or add additional context in comments.

Comments

0

It is normal in Python to import each module that is needed with in each. Don't count on any 'global' imports. In fact there isn't such a thing. With one exception. I discovered in

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

that %run -i myscript runs the script in the Ipython interactive namespace. So for quick test scripts this can save a bunch of imports.

I don't see the need for this triple import

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

If all you are using from WC_class just use the last line.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.