Ошибка Python при вызове NumPy из метода класса с картой

Следующий код вызывает ошибку:

Traceback (most recent call last):
  File "", line 25, in <module>
    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'

код:

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)

Я считаю, что совершил серьезную ошибку, потому что кажется, что Python интерпретирует "np" из NumPy как целое число, но я не вижу, почему это так.

Ответы

Ответ 1

Я попытаюсь добавить точный ответ на те, которые уже были даны. numpy.sqrt имеет некоторые ограничения, которые math.sqrt не имеет.

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

возвращает (с 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'

Фактически, 2 ** 64 равно 18,446,744,073,709,551,616 и, согласно стандарту типов данных C (версия C99), тип long long unsigned integer содержит, по крайней мере, диапазон между 0 и 18,446,744,073,709,551,615.

AttributeError происходит потому, что numpy, вид того, что он не знает, как обрабатывать (после преобразования в тип данных C), по умолчанию используется метод sqrt для объекта (но это doesn ' t существует). Если мы используем float вместо целых чисел, то все будет работать с помощью numpy:

import numpy  # version 1.13.3

print(numpy.sqrt(float(2 ** 64)))

возвращает:

4294967296.0

Поэтому вместо замены numpy.sqrt на math.sqrt вы можете вместо этого заменить calc = np.sqrt(food ** 5) на calc = np.sqrt(float(food ** 5)) в вашем коде.

Я надеюсь, что эта ошибка будет иметь для вас больше смысла.

Ответ 2

Как заметили другие, это сводится к тому, что np.sqrt(7131 ** 5) работает, но np.sqrt(7132 ** 5) возвращает ошибку:

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'

Так как np.sqrt docs не упоминает никаких ограничений в аргументе, я бы счел это ошибкой numpy.

Ответ 3

Вы можете заменить numpy встроенной функцией math.sqrt следующим образом:

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

Я думаю, что проблема вашего кода в том, что вы, вероятно, достигли предела (пока не уверен, почему он вызывает эту запутанную ошибку), потому что 10000 ** 5 является большим числом. Вы можете проверить это, уменьшив диапазон (10000) до диапазона (1000). Вы заметите, что ваш код работает отлично:

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

Это отлично работает, просто уменьшая диапазон (10000) до диапазона (1000)

Ответ 4

Обычный Python

На самом деле вам не нужны ни numpy, ни math, потому что sqrt(x) - x**0.5. Итак:

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

Это означает, что вы можете заменить свой код:

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

Если вы хотите использовать NumPy, вы можете наслаждаться тем, что вы можете работать с массивами, как если бы они были скалярами:

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

Короткое рефакторинг

Удаление всех ненужных объектно-ориентированных-с-странными именами, ваш код будет выглядеть следующим образом:

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