#python #numpy #integer #range
#python #numpy #целое число #диапазон
Вопрос:
Вчера я задал здесь вопрос о странном поведении python range()
. Я случайно использовал range()
вместо np.arange()
. Но в зависимости от входного int-типа он работает для математических операций или нет. Это было в огромном контексте, поэтому я упростил задачу.
import numpy as np
"""
DOES WORK
"""
x1 = np.intc(545)
x2 = np.intc(1048)
x_axis = range(x1, x2)
test = (x_axis - x1) # should throw exception, but works
type(x_axis[0]) # numpy.int32 / intc
"""
DOESNT WORK
"""
t1 = 545
t2 = 1048
t_axis = range(t1, t2)
test2 = (t_axis - t1) # throws TypeError unsupported operand type(s) for -: 'range' and 'int'
Предыстория:
Причина использования intc-datatype заключается в том, что моя программа выполняет некоторые другие задачи, такие как поиск пиков и т. Д., И я использую некоторые списки для создания списка из вычисленных пиков. После некоторых других шагов я использую x1 и x2 из этого списка пиков (который, очевидно, не является обычным списком целых чисел). Итак, вчера я изменил свой код и сгенерировал новый список, а затем произошло исключение. Я предполагаю, что numpy / scipy использует внутренний intc.
Может ли кто-нибудь объяснить такое поведение?
Ответ №1:
Последовательности и скаляры Python ведут себя иначе, чем массивы и скаляры numpy 1d. Давайте рассмотрим несколько основных примеров, чтобы разобраться в этом (или перейдем к нижней части, если спешите):
# define our test objects
a_range = range(2,6)
a_list = list(a_range)
a_array = np.array(a_list)
# ranges don't add
a_range a_range
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: unsupported operand type(s) for : 'range' and 'range'
# lists do add but with different semantics ...
a_list a_list
# [2, 3, 4, 5, 2, 3, 4, 5]
# ... from numpy arrays
a_array a_array
# array([ 4, 6, 8, 10])
# what happens if we mix types?
# range and list don't mix:
a_range a_list
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: unsupported operand type(s) for : 'range' and 'list'
# but as soon as there is a numpy object involved it "wins":
a_range a_array
# array([ 4, 6, 8, 10])
a_list a_array
# array([ 4, 6, 8, 10])
# How about scalars?
py_scalar = 3
np_scalar = np.int64(py_scalar)
# again, in pure python you cannot add something to a range ...
a_range py_scalar
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: unsupported operand type(s) for : 'range' and 'int'
# or a list
a_list py_scalar
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: can only concatenate list (not "int") to list
# but you can add a Python or numpy scalar to a numpy object
a_array py_scalar
# array([5, 6, 7, 8])
a_array np_scalar
# array([5, 6, 7, 8])
# Now if the scalar is a numpy object, again, it "wins":
a_range np_scalar
# array([5, 6, 7, 8])
a_list np_scalar
# array([5, 6, 7, 8])
Итак, подводя итог, последовательности Python и массивы numpy 1d имеют разную семантику, в частности, с двоичными операторами, такими как » » или «-» или «*». Если хотя бы один операнд является объектом numpy (массивом или скаляром), выигрывает numpy: объекты, отличные от numpy, будут преобразованы (плоские последовательности становятся одномерными массивами), и будет применяться семантика numpy.
Комментарии:
1. Спасибо за ваш подробный ответ! Теперь я знаю немного больше о поведении 😉