Python error when calling NumPy from class method with map

前端 未结 5 1666
我寻月下人不归
我寻月下人不归 2021-02-12 23:58

The following code throws me the error:

Traceback (most recent call last):
  File \"\", line 25, in 
    sol = anna.main()
  File \"\", line 17, in         


        
相关标签:
5条回答
  • 2021-02-13 00:15

    Plain Python

    Actually, you need neither numpy nor math because sqrt(x) is x**0.5. So:

    sqrt(x**5) = x ** (5/2) = x ** 2.5
    

    It means you could replace your code with:

    class anaconda():
        def __init__(self):
            self.mice = range(10000)
    
        def eat(self, food):
            calc = food ** 2.5
            return calc
    
        def main(self):
            sol = list(map(self.eat, self.mice))
            return sol
    
    
    if __name__ == '__main__':
        anna = anaconda()
        sol = anna.main()
        print(len(sol))
    

    NumPy

    If you want to use NumPy, you can enjoy the fact that you can work with arrays as if they were scalars:

    import numpy as np
    
    class anaconda():
    
        def __init__(self):
            self.mice = np.arange(10000)
    
        def eat(self, food):
            return food ** 2.5
    
        def main(self):
            return self.eat(self.mice)
    
    
    if __name__ == '__main__':
        anna = anaconda()
        sol = anna.main()
        print(len(sol))
    

    Short refactor

    Removing all the unneeded object-oriented-with-weird-names, your code becomes:

    import numpy as np
    print(np.arange(10000) ** 2.5)
    
    0 讨论(0)
  • 2021-02-13 00:17

    I'll try to add a precise answer to those that have already been given. numpy.sqrt has some limitations that math.sqrt doesn't have.

    import math
    import numpy  # version 1.13.3
    
    print(math.sqrt(2 ** 64 - 1))
    print(numpy.sqrt(2 ** 64 - 1))
    
    print(math.sqrt(2 ** 64))
    print(numpy.sqrt(2 ** 64))
    

    returns (with Python 3.5) :

    4294967296.0
    4294967296.0
    4294967296.0
    Traceback (most recent call last):
      File "main.py", line 8, in <module>
        print(numpy.sqrt(2 ** 64))
    AttributeError: 'int' object has no attribute 'sqrt'
    

    In fact, 2 ** 64 is equal to 18,446,744,073,709,551,616 and, according to the standard of C data types (version C99), the long long unsigned integer type contains at least the range between 0 and 18,446,744,073,709,551,615 included.

    The AttributeError occurs because numpy, seeing a type that it doesn't know how to handle (after conversion to C data type), defaults to calling the sqrt method on the object (but that doesn't exist). If we use floats instead of integers then everything will work using numpy:

    import numpy  # version 1.13.3
    
    print(numpy.sqrt(float(2 ** 64)))
    

    returns:

    4294967296.0
    

    So instead of replacing numpy.sqrt by math.sqrt, you can alternatively replace calc = np.sqrt(food ** 5) by calc = np.sqrt(float(food ** 5)) in your code.

    I hope this error will make more sense to you now.

    0 讨论(0)
  • 2021-02-13 00:23

    As others have noticed, this boils down to the fact that np.sqrt(7131 ** 5) works but np.sqrt(7132 ** 5) returns an error:

    import numpy as np
    
    print(np.sqrt(7131 ** 5))
    print(np.sqrt(7132 ** 5))
    
    # 4294138928.9
    Traceback (most recent call last):
      File "main.py", line 4, in <module>
        print(np.sqrt(7132 ** 5))
    AttributeError: 'int' object has no attribute 'sqrt'
    

    Since np.sqrt docs don't mention any bounds on the argument, I'd consider this a numpy bug.

    0 讨论(0)
  • 2021-02-13 00:23

    You can replace numpy by the built in function math.sqrt like this:

    import math  
    
    class anaconda():
    
        def __init__(self):
            self.mice = range(10000)
    
        def eat(self, food):
            calc = math.sqrt(food ** 5)
            return calc
    
        def main(self):
    
            sol = list(map(self.eat, self.mice))
            return sol
    
    
    if __name__ == '__main__':
        anna = anaconda()
        sol = anna.main()
        print(len(sol))
    

    I think that the problem of your code is that you are probably reaching a limit (not sure yet why it raises that confusing error) because 10000**5 is a reeeally big number. You can check this out by reducing your range(10000) to range(1000). You will notice that your code runs perfectly fine then:

    import numpy as np  
    
    class anaconda():
    
        def __init__(self):
            self.mice = range(1000)
    
        def eat(self, food):
            calc = np.sqrt((food ** 5))
            return calc
    
        def main(self):
    
            sol = list(map(self.eat, self.mice))
            print sol
            return sol
    
    
    if __name__ == '__main__':
        anna = anaconda()
        sol = anna.main()
        print(len(sol))
    

    This runs perfectly fine, just by reducing range(10000) to range(1000)

    0 讨论(0)
  • 2021-02-13 00:33

    It may not be your exact case, but if you want to take the square root of a large number AND you want to have control of the precision of the result, going either to math.sqrt() or x ** 0.5 would not be much useful because your result will end up being a float number, and for large enough inputs, this will hit the limitations of float numbers.

    One possibility for the specific case of sqrt is to look into an integer-only implementation of the square root algorithm, e.g. flyingcircus.util.isqrt() (Disclaimer: I am the main author of flyingcircus).

    Alternatively, for a more general solution, one may look into gmpy (or any other arbitrary precision library with Python bindings).

    0 讨论(0)
提交回复
热议问题