0

I'm developing a module that should be able to interact with other modules such as numpy or PIL. To accept parameters and test if, for example, a parameter is an numpy.ndarray, I'd need to import numpy first.

What I used to do on previous projects is

numpy_exists = True
try:
    import numpy as np
except:
    numpy_exists = False

Then, when accepting parameters that could be of type <type numpy.ndarray> I checked it like that:

    if numpy_exists and type(param) == np.ndarray:
        # ...

Now, it works, but it feels very weak because (personally) I look at the statement and the only thing I see is the NameError this code could raise. Of course, it doesn't raise the error, but code like that makes me feel awkward when looking at it.

Is this a good way to handle the problem? Is there a better one?

  • What I don't understand is why would be missing a package that your module needs. I mean, if your module needs numpy in order to interact with it, just add required packages in the project's setup.py file. – miso Mar 10 '18 at 10:16
  • The catch is that my module does not need numpy. It can interact with numpy, if it helps the user's convenience. For example, the user can pass a file stream (of an image, for example) or a numpy array that represents a cv2 image. Then if the user does not want to have cv2 and numpy involved, they don't have to. – Yotam Salmon Mar 10 '18 at 10:27
2

I think that this is generally fine. But from a design standpoint, I'd probably solve it by moving the type checking for parameters in my own function (or even into a decorator, which looks much nicer). Then you can provide two different functions, depending on whether numpy exists or not, and don't even incur any speed cost. E.g:

def typecheck_without_numpy(...):
    ...

def typecheck_with_numpy(...):
    ...

try: 
    import numpy
    typecheck = typecheck_with_numpy
except ImportError:
    typecheck =  typecheck_without_numpy


def some_function(x):
    typecheck(x)

Of course, you can rename typecheck to something like type_check_and_cast and then either make it convert x to something your function can handle, or raise a TypeError. This way, your code isn't littered by type checks, and as I said, you could move the typecheck into a decorator, so your functions would look something like

@typecheck
def some_function(x):
   ...
  • Must admit this looks much cleaner like you did it. Thanks. – Yotam Salmon Mar 10 '18 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.