4

I have some interface class, if numpy is available I would provide some extra method for the class (faster implementation)

It is possible to define some function based on the success of an import, but the same code does not work for class methods.

This code

try:
    import numpy

    def main2():
        ret_array= numpy.array([],dtype=numpy.double)
        return ret_array
except ImportError:
    def main2():
        print ("do nothing")

successfully defines a main2() which returns an empty numpy array

But this code

class xxx:
    try:
        import numpy

        def main2():
            ret_array= numpy.array([],dtype=numpy.double)
            return ret_array
    except ImportError:
        def main2():
            print ("do nothing")

results in an exception if I try to call main2()

xxx.main2()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "test2.py", line 17, in main2
    ret_array= numpy.array([],dtype=numpy.double)
NameError: name 'numpy' is not defined

Is there some other way to achieve this? (based on the availability of a module define a class method differently)

wjandrea
  • 28,235
  • 9
  • 60
  • 81
nobs
  • 708
  • 6
  • 25
  • 2
    Because your `import numpy` is inside the class, `numpy` becomes a class variable (`xxx.numpy` in place of `numpy` would work, although I suspect that it isn't the recommended approach). – alani Dec 05 '21 at 18:34
  • You can try to check is the imported module present: https://stackoverflow.com/questions/4858100/how-to-list-imported-modules – IgorZ Dec 05 '21 at 18:36
  • 2
    One possible approach would be (at the top, outside of the class) `try: import numpy` `except ImportError: numpy=None`, and then inside your class definition you can use `if numpy:` .... `else:` .... with alternative definitions for `main2` depending whether `numpy` is available or not. Any references to `numpy` will then just use `numpy` rather than having to use `xxx.numpy`. – alani Dec 05 '21 at 18:41

5 Answers5

1
try:
    import numpy

    class xxx:
        def main2(self):
            ret_array = numpy.array([],dtype=numpy.double)
            print(ret_array)
except:
    class xxx:
        def main2(self):
            print("do nothing")
Shay Nehmad
  • 1,103
  • 1
  • 12
  • 25
  • This will not work (or at least not reasonable) The class has already like 20 methods, so I would need to do two full definitions – nobs Dec 05 '21 at 18:37
  • 1
    What if there are other parts in the class definition? It'd be annoying to copy-paste all of them. Maybe it'd be better to use `type()` to build the class manually. – wjandrea Dec 05 '21 at 18:38
  • @nobs I literally tested it locally, and it works. – Shay Nehmad Dec 05 '21 at 18:38
  • @wjandrea There are other syntax options, but I assume that OP wants what they asked for :) – Shay Nehmad Dec 05 '21 at 18:39
1

You could try:

class Test:
    def test(self):        
        try:
            import numpy
            import_succeeded = True
        except:
            import_succeeded = False
        
        if import_succeeded:
            pass
        else:
            pass
Franco Piccolo
  • 6,845
  • 8
  • 34
  • 52
  • I imported numpy globally '''try: import numpy numpy_defined = True except ImportError: numpy_defined = False''' and defined the function based on the bool variable -> this works – nobs Dec 05 '21 at 18:43
  • 1
    @nobs To be honest, you don't even need the boolean. Just set `numpy=None` if the import fails (provided obviously that you then test it and don't just use it regardless). Though also, unless there is a very good reason to do the import inside the class, I would just do it at the top of the module. – alani Dec 05 '21 at 18:45
1

Thanks for all the hints I received

the solution I'm going to use is:

try:
    import numpy
except ImportError:
    numpy = None

class xxx:

    if numpy:
        def main2():
            ret_array= numpy.array([],dtype=numpy.double)
            return ret_array
    else:
        def main2():
            print ("do nothing")
nobs
  • 708
  • 6
  • 25
  • 2
    Glad you agreed with this suggestion :) One last thing: if you are intending that your `main2` method is bound to instances of the class (rather than a static method), then you are going to need the `self` argument. – alani Dec 05 '21 at 18:57
  • 1
    @alani Yes I know! I tried to remove everything from the source which is not relevant to the question. I already checked in the code, Tested it with some huge arrays and is staggering how fast numpy is vs standard list. :-) – nobs Dec 06 '21 at 20:41
1

Importing (again) the module inside of 1st version of main2() will work.

class xxx:
    try:
        import numpy
        def main2():
            import numpy
            ret_array= numpy.array([],dtype=numpy.double)
            return ret_array
    except ImportError:
        def main2():
            print ("do nothing")

y = xxx.main2()
print(y)
Marcel Preda
  • 1,045
  • 4
  • 18
0

Use ABC

from abc import ABC, abstractmethod

class ICalculator(ABC):
  @abstractmethod
  def calculate(self) -> int:
    pass

class CalculatorNoNumPy(ICalculator):
    def calculate(self):
      return 7

class CalculatorWithNumPy(ICalculator):
    def calculate(self):
      return 9

try:
  import YouCantFindMe # TODO: replace with numpy
  calculator = CalculatorWithNumPy()
except ImportError:
   calculator = CalculatorNoNumPy()

print(calculator.calculate())
balderman
  • 22,927
  • 7
  • 34
  • 52