Peter Becich
Peter Becich

Reputation: 1053

Python: free variable 'numpy' referenced before assignment in enclosing scope

I am adding some code into an existing class for testing purposes. Normally this class, eigensystem_CUDA_implementation, relies on some functions and attributes of its parent. When this class is imported independently of the rest of the program, I'd like to substitute the usual parent class for a testParent class.

If this is a bad way to test code and I should do this completely differently, I'm open to that suggestion.

When initializing an eigensystem_CUDA_implementation object, the error is:

NameError: free variable 'np' referenced before assignment in enclosing scope

which traces back to the line self.mat = np.matrix(...

There is much more that relies on NumPy and pyCUDA in eigensystem_CUDA_implementation that is not shown. Can a class import a module that it relies on? Haven't tested this yet because of the first error.

class eigensystem_CUDA_implementation:
    def __init__(self, parent = None, max_time = 60, delta = 10**(-32)):
            # For testing purposes, when class is utilized independently
            if(not parent):
                    # testing mode
                    if(not sys.modules.has_key("numpy")):
                            import numpy as np
                            import pycuda.driver as cuda
                            import pycuda.autoinit
                            from pycuda.compiler import SourceModule
                    class testParent:
                            def __init__(self, size = 10):
                                    self.size = size
                                    self.delta = 10**(-32)
                                    self.num_site_types = 8
                                    self.mat =  np.matrix(np.random.random((self.size,self.size)).astype(np.float64))
                            def get_mutation_selection_matrix(self, alpha):
                                    return self.mat
    ...

One potential problem: not sys.modules.has_key("numpy") would show NumPy as imported whether it is named "np" or something else. The rest of the code uses "np" though so I'm ignoring this.

Thanks for any suggestions

Upvotes: 2

Views: 6508

Answers (2)

BrenBarn
BrenBarn

Reputation: 251353

Your code will fail if numpy is already imported. You only import it inside the if block, so if it's already imported it won't be defined inside that block. But later in the same function you reference np as a local variable.

Anyway, you don't really need to worry about importing numpy. Just do import numpy as np unconditionally. If it's already imported, it will just re-use the imported version. It won't waste memory or anything importing it twice.

That said, this code looks rather unwieldy and fragile. You should see if there's a better way to do this, by for instance defining a separate function that patches up the class with the necessary attributes. Having a class and an import inside a method inside another class is getting pretty hairy.

Upvotes: 3

Blckknght
Blckknght

Reputation: 104712

When you put an import within a function, like you're doing in __init__, the variable that the module gets assigned to is local to that function. If you want it to be a global variable, you need to make it one explicitly with a global statement. global np, cuda, SourceModule may do it.

Also, it may not be enough to check for numpy in sys.modules before using np, as numpy could have been imported by a different module, rather than the current one. You could check np in locals(), but it might be easier to simply do the imports unconditionally.

Upvotes: 1

Related Questions