Следующие примеры не приводят к симметричным результатам:
np.promote_types("float32", "m8")
# returns "m8", which is probably wrong
np.promote_types("m8", "float32")
# raises TypeError.
То же верно и для всех других типов с плавающей запятой. Интересно, есть ли в этом какая-то странная логика, как взлом, позволяющий определенные вызовы ufunc, но я еще не нашел его.
Похоже, что по крайней мере np.multiply поддерживает это.
import numpy as np
print(np.multiply(np.timedelta64(1), 1.2))
Я думаю, что вышесказанное тоже следует считать ошибкой.
Я думаю, что вопрос всегда в том, что для ufuncs «правила литья реализуются с помощью вопроса о том, когда тип данных может быть« безопасно »преобразован в другой тип данных», как описано в документации. Похоже, есть исключения, подобные приведенным выше, когда приведение типов небезопасно, но мы заставили ufunc работать. Я предполагаю, что в этом случае Promote_types все равно должен сообщать о недопустимом продвижении типа (как для np.promote_types ("float32", "m8"), так и для np.promote_types ("m8", "float32")). Вопрос о том, нужно ли нам продолжать работу ufunc, можно решать в индивидуальном порядке?
Да, мы должны четко различать, что np.promote_types
должно быть общим правилом, которое всегда разумно. Вот почему мне нравится термин «обычный dtype». Это, например, dtype, который можно использовать с np.concatenate
.
Каждый ufunc индивидуально может решить реализовать определенную операцию, используя «общий dtype» или другую логику. Мы специально делаем это для multiple и timedelta64, так что это действительно отдельная проблема.
Я полагаю, что мы фактически не используем эту логику во многих местах, поскольку ufuncs в основном полагаются на np.can_cast(..., ...)
как вы заметили. И хотя это обычно связано с продвижением шрифтов, здесь этого нет.
Учитывая приведенное выше обсуждение, я пошел дальше и добавил исправление для Promo_types.