6.8. Операторы¶
Первый вид математики, которую numpy выполняет над ndarray, – это стандартные операторы Python. Арифметические операторы, операторы сравнения и побитовые операторы работают поэлементно – каждый оператор проходит массив (или оба массива) один раз от начала до конца внутри одного вызова библиотеки, что намного быстрее, чем эквивалентный цикл for на Python.
6.8.1. Арифметика¶
+, -, *, /, //, %, ** работают между двумя массивами совместимой формы или между массивом и скаляром:
a = np.array([1, 2, 3, 4], dtype=np.float)
b = np.array([10, 20, 30, 40], dtype=np.float)
print(a + b) # array([11.0, 22.0, 33.0, 44.0])
print(a * 2) # array([2.0, 4.0, 6.0, 8.0])
print(b - a) # array([9.0, 18.0, 27.0, 36.0])
print(b / a) # array([10.0, 10.0, 10.0, 10.0])
Dtype результата следует правилам повышения типов, описанным в Dtypes. Целочисленные массивы переполняются по модулю; приведите их к более широкому dtype перед операцией, когда это важно.
Оператор матричного умножения @ не реализован. Используйте dot() для матричных / векторных произведений.
6.8.1.1. Формы на месте¶
Каждый арифметический оператор имеет форму на месте – +=, -=, *=, /=, %=, **=. Форма на месте записывает результат прямо в существующий буфер, а не выделяет временный:
b = b + 1 # allocates a temporary the size of b
b += 1 # no temporary
На микроконтроллере вторая форма по сути обязательна для любого горячего цикла.
6.8.2. Побитовые операции¶
Побитовые операторы &, |, ^ работают поэлементно над целочисленными массивами. Применённые к массиву float или complex, они вызывают TypeError:
a = np.array([0b1100, 0b1010], dtype=np.uint8)
b = np.array([0b1010, 0b1100], dtype=np.uint8)
print(a & b) # array([8, 8], dtype=uint8)
print(a | b) # array([14, 14], dtype=uint8)
print(a ^ b) # array([6, 6], dtype=uint8)
Унарный ~ выполняет побитовое НЕ над целочисленным массивом.
Операторы сдвига << и >> не подключены на уровне операторов Python. Функциональные формы left_shift() и right_shift() работают:
np.left_shift(a, 2)
np.right_shift(b, 1)
6.8.3. Сравнение¶
==, !=, <, <=, >, >= все возвращают ndarray типа bool формы широковещания:
a = np.array([1, 2, 3, 4, 5], dtype=np.uint8)
print(a < 3)
# array([True, True, False, False, False], dtype=bool)
Логический результат – это именно то, что потребляют индексация и Выборка и перестановка.
6.8.3.1. Правило стороны¶
ndarray должен находиться слева от оператора отношения при сравнении со скаляром. a > 2 работает; 2 < a вызывает TypeError. Для симметричной формы используйте имена функций:
np.greater(5, a) # 5 > a, element-wise
np.less(5, a) # 5 < a, element-wise
np.equal(5, a) # 5 == a, element-wise
np.not_equal(5, a) # 5 != a, element-wise
6.8.4. Унарные операторы¶
+a– возвращает копию массива.-a– отрицание. На беззнаковых dtype значения переполняются по модулю \(2^N\) так же, как и у бинарных операторов.abs(a)– поэлементное абсолютное значение. На беззнаковых dtype возвращает копию без вычислений.~a– побитовая инверсия (только целочисленные массивы).len(a)– возвращает длину первой оси, согласно соглашению о последовательностях Python.
6.8.5. Чего не хватает¶
Правосторонние операторы для сравнения и некоторых побитовых операций не реализованы так, как арифметические операторы. Используйте функциональные формы (выше), когда ndarray оказывается справа.
Полный список поддерживаемых операторов и правила повышения типов, которым они следуют, см. в numpy — numpy-совместимые операции с массивами.