Error de Python al llamar a NumPy desde el método de clase con mapa

El siguiente código me lanza el error:

Traceback (most recent call last): File "", line 25, in  sol = anna.main() File "", line 17, in main sol = list(map(self.eat, self.mice)) File "", line 12, in eat calc = np.sqrt((food ** 5)) AttributeError: 'int' object has no attribute 'sqrt' 

Código:

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

Creo que cometí un grave error, porque parece que Python interpreta el ‘np’ de NumPy como un número entero, pero no tengo idea de por qué.

Intentaré agregar una respuesta precisa a las que ya se han dado. numpy.sqrt tiene algunas limitaciones que math.sqrt no tiene.

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

Devoluciones (con Python 3.5):

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

De hecho, 2 ** 64 es igual a 18,446,744,073,709,551,616 y, según el estándar de los tipos de datos C (versión C99), el tipo de long long unsigned integer contiene al menos el rango entre 0 y 18,446,744,073,709,551,615 incluido.

El AttributeError produce porque numpy , al ver un tipo que no sabe cómo manejar (después de la conversión al tipo de datos C), utiliza de forma predeterminada el método sqrt en el objeto (pero eso no existe). Si usamos flotadores en lugar de enteros, todo funcionará usando numpy :

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

devoluciones:

 4294967296.0 

Entonces, en lugar de reemplazar numpy.sqrt por math.sqrt , alternativamente puede reemplazar calc = np.sqrt(food ** 5) por calc = np.sqrt(float(food ** 5)) en su código.

Espero que este error tenga más sentido para ti ahora.

Como otros han notado, esto se reduce al hecho de que np.sqrt(7131 ** 5) funciona, pero np.sqrt(7132 ** 5) devuelve un 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  print(np.sqrt(7132 ** 5)) AttributeError: 'int' object has no attribute 'sqrt' 

Dado que los documentos np.sqrt no mencionan ningún np.sqrt en el argumento, considero que esto es un error numpy.

Puede reemplazar numpy por la función incorporada math.sqrt de esta manera:

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

Creo que el problema de su código es que probablemente esté llegando a un límite (aún no estoy seguro de por qué genera ese error confuso) porque 10000 ** 5 es un número realmente grande. Puede verificar esto reduciendo su rango (10000) a rango (1000). Notarás que tu código funciona perfectamente bien entonces:

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

Esto funciona perfectamente bien, simplemente reduciendo el rango (10000) al rango (1000)

Python llano

En realidad, no necesita numpy ni math porque sqrt(x) es x**0.5 . Asi que:

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

Significa que podrías reemplazar tu código con:

 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

Si desea usar NumPy, puede disfrutar el hecho de que puede trabajar con matrices como si fueran escalares:

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

Refactor corto

Al eliminar todos los nombres innecesarios orientados a objetos con nombres extraños, su código se convierte en:

 import numpy as np print(np.arange(10000) ** 2.5) 

Puede que no sea su caso exacto, pero si desea obtener la raíz cuadrada de un gran número Y desea tener el control de la precisión del resultado, vaya a math.sqrt() o x ** 0.5 no sería muy útil porque su resultado terminará siendo un número flotante, y para entradas suficientemente grandes, esto afectará las limitaciones de los números flotantes.

Una posibilidad para el caso específico de sqrt es buscar una implementación de algoritmo de raíz cuadrada solo para enteros, por ejemplo, flyingcircus.util.isqrt() (Descargo de responsabilidad: soy el autor principal de flyingcircus ).

Alternativamente, para una solución más general, uno puede buscar en gmpy (o en cualquier otra biblioteca de precisión arbitraria con enlaces Python).