2

I'm trying to learn how to do object oriented coding for scientific computing running a simulation; I'm using using numpy, etc. I've created my first class, WC_unit, which is located at ./classes/WC_class.py (a subdirectory). I've created an __init__.py file (which is empty) in the classes directory.

The methods for the WC_unit class require some numpy functions, like exp

When I run the code (in ipython) from the terminal, using

%run WC_class.py

I can generate an instance of the class E1 = WC_unit() and I can run the associated methods on it, ie E1.update() I can't really tell if it's working. I wrote some outer code in a script test.py located at . (above ./classes) to test the objects I'm generating and I'm trying to import the class by using

from classes.WC_class import WC_unit

Now, when I create an instance E1 of the class and run E1.update(), I get the error message global name 'exp' is not defined.

I've tried calling from numpy import * or also import numpy as np and changing the function call to np.exp() and I continue to get the error. Thinking that I had some sort of scoping problem or issues with namespace I've put this same import function at various locations, including in the test.py file, the top of the class file WC_class.py, even in the method:

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))

I would really like to up my game and figure out how to write my own classes and use them with the awesome computing tools. I guess I'd like to know:

  1. What am I doing wrong (probably a lot, I suspect). I think it's something with how I'm importing my class? but perhaps also scoping in the class itself.

  2. Why does my class lose access to the numpy functions when I import it, but not when I run it like a script in the terminal?

  3. I guess I also generally don't understand why people are so protective of their namespaces, i.e. why do so many code examples show import numpy as np and use all of the functions as np.exp(x), etc. I don't have much of a computer science background so I could benefit a lot from any explanations you could provide- the documentation is kind of cryptic to me.

Python version: 2.7.8 |Anaconda 2.1.0 (x86_64)| (default, Aug 21 2014, 15:21:46) [GCC 4.2.1 (Apple Inc. build 5577)] On Mac OSX 10.6.8

ali_m
  • 71,714
  • 23
  • 223
  • 298
steeles
  • 169
  • 1
  • 11
  • Stop doing `from numpy import *` and prefer `import numpy` and using `numpy.array`, `numpy.mean`, etc. This prevents namespace pollution which creates problems like you are seeing. – Cory Kramer Feb 10 '15 at 19:23
  • Please always show the *full traceback* for any error message in your question – ali_m Feb 10 '15 at 20:37

1 Answers1

1

When you call %run WC_class.py in IPython, what you are doing is loading the contents of that source file directly into the interactive namespace. Because you've already called from numpy import * within your IPython session, exp is defined as numpy.exp within the set of globals for the current 'module' (which, in this case, is just the IPython interactive namespace), so when you call exp() in WC_unit.update() (or anywhere else within WC_class.py) it will work fine.

However, you do not do a from numpy import * at the top of test.py, therefore when you import WC_unit into your script exp has not been defined within the scope of the current module (which is now the test script).

You've tried from numpy import * within the WC_unit.update() method itself, but this will fail because import * is only allowed at a module level (in fact you should have seen a SyntaxWarning about this when you tried to import WC_unit!). Since the import fails, exp is still undefined and the WC_unit.update() method will raise the NameError you're seeing.

What you ought to do is have a single import line at the top of any source file that uses numpy functions:

import numpy as np

then refer to any numpy functions via the np. namespace.


Regarding your third point, the main reason to do

import numpy as np

x = np.exp(y) # etc.

rather than

from numpy import *

x = exp(y)   # etc.

is that the latter method pollutes your global namespace.

Suppose you had already defined your own function called exp. When you do from numpy import *, you will be overwriting your own function called exp with numpy.exp, so when you later call exp(y) it might not do what you expect it to. For example, this is exactly what happens to some of the built-in Python functions such as sum and all:

print(sum.__module__)
# __builtin__

from numpy import *

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

What's more, this is more-or-less irreversible - once you've done a from module import * there's no easy way to get rid of the stuff you've imported to your namespace (or restore any old modules or variables you've clobbered by importing over the top of them).

As long as you keep all of the contents of each module in its own separate namespace there is no risk of namespace collisions, and no ambiguity about where each function or class comes from. By convention we use np to refer to the namespace for numpy, plt for matplotlib.pyplot etc.

Community
  • 1
  • 1
ali_m
  • 71,714
  • 23
  • 223
  • 298
  • Thank you! I'm not sure if this is exactly what's going on, but I've definitely been able to learn a bit more about how classes and objects work, and break things down into smaller chunks. I'll probably be asking a few more philosophical-type questions as I learn how to write, I appreciate your thorough and straightforward answer. If anyone can link me to any tutorials about how to develop simulations using classes and such I would love to read them. in particular i'm having trouble figuring out how to structure my files... modules... – steeles Feb 11 '15 at 00:29