Как мы используем sin, cos, tan в общем (включая пользователя- определенные типы) в Python?

Edit: Позвольте мне попытаться перефразировать и улучшить свой вопрос. Старая версия прикреплена внизу.

Я ищу способ выразить и использовать бесплатные функции в типовой форме. Примеры:

abs(x)  # maps to x.__abs__()
next(x) # maps to x.__next__() at least in Python 3
-x      # maps to x.__neg__()

В этих случаях функции были разработаны таким образом, чтобы позволить пользователям с пользовательскими типами настраивать свое поведение, делегируя работу вызову нестатического метода. Это хорошо. Это позволяет нам писать функции, которые на самом деле не заботятся о точных типах параметров, если они «ощущаются» как объекты, моделирующие определенную концепцию.

Примеры счетчиков: Функции, которые не могут быть легко использованы в общем виде:

math.exp  # only for reals
cmath.exp # takes complex numbers

Предположим, я хочу написать универсальную функцию, которая применяет exp к списку числовых объектов. Какую функцию exp я должен использовать? Как выбрать правильный?

def listexp(lst):
    return [math.exp(x) for x in lst]

Очевидно, что это не сработает для списков комплексных чисел, даже если для комплексных чисел есть exp (в cmath). И это также не будет работать для любого определенного пользователем числового типа, который может предлагать свою собственную специальную функцию exp.

Итак, я ищу способ справиться с этим с обеих сторон - в идеале без спец кожух много чего. Как автор некоторой универсальной функции, которая не заботится о точных типах параметров, я хочу использовать правильные математические функции, специфичные для задействованных типов, без необходимости иметь дело с этим явно. Как писатель определяемого пользователем типа, я хотел бы предоставить специальные математические функции, которые были расширены для работы с дополнительными данными, хранящимися в этих объектах (аналогично мнимой части комплексных чисел).

Каков предпочтительный шаблон / протокол / идиома для этого? Я еще не тестировал numpy . Но я скачал его исходный код. Насколько я знаю, он предлагает функцию sin для массивов. К сожалению, я пока не нашел его реализации в исходном коде. Но было бы интересно посмотреть, как им удалось выбрать правильную функцию sin для правильного типа чисел, которые в настоящее время хранятся в массиве.

В C ++ я бы полагался на перегрузку функций и ADL (поиск, зависимый от аргументов). Поскольку C ++ статически типизирован, неудивительно, что это (поиск имени, разрешение перегрузки) полностью обрабатывается во время компиляции. Полагаю, я мог бы эмулировать это во время выполнения с помощью Python и инструментов отражения, которые Python может предложить. Но я также знаю, что попытка импортировать стиль кодирования на другой язык может быть плохой идеей и не очень идиоматической для нового языка. Так что, если у вас есть другая идея для подхода, я все слышу.

Думаю, где-то в какой-то момент мне нужно вручную выполнить некоторую зависящую от типа диспетчеризацию расширяемым способом. Может быть, написать модуль «tgmath» (типовая математика), который будет поддерживать реальную и сложную поддержку, а также позволит другим регистрировать свои типы и специальные функции ... Мнения? Что говорят об этом мастера Python?

TIA

Edit: Видимо, я не единственный, кто интересуется универсальными функциями и перегрузкой, зависящей от типа. Существует PEP 3124 , но он находится в стадии черновика 4 года назад.


Старая версия вопроса:

У меня большой опыт работы с Java и C ++, и я только недавно начал изучать Python. Что меня интересует: как расширить математические функции (по крайней мере, их имена), чтобы они работали с другими определяемыми пользователем типами? Предлагают ли такие функции какие-либо точки / ловушки расширения, которые я могу использовать (аналогично протоколу итератора, где next (obj) фактически делегирует obj .__ next __ и т. Д.)?

В C ++ я бы просто перегрузил функцию новым типом параметра и попросил компилятор выяснить, какая из функций имеется в виду, используя статические типы выражений аргументов. Но поскольку Python - очень динамичный язык, перегрузки не существует. Какой способ Python предпочитает делать это?

Кроме того, когда я пишу собственные функции, я бы хотел избежать длинных цепочек из

if isinstance(arg,someClass):
    suchandsuch
elif ...

Какие шаблоны я мог бы использовать, чтобы код выглядел красивее и более питонски?

Я думаю, я в основном пытаюсь справиться с отсутствием перегрузки функций в Python. По крайней мере, в C ++ перегрузка и поиск, зависящий от аргументов, являются важной частью хорошего стиля C ++.

Можно ли заставить

x = udt(something)  # object of user-defined type that represents a number
y = sin(x)          # how do I make this invoke custom type-specific code for sin?
t = abs(x)          # works because abs delegates to __abs__() which I defined.

работать? Я знаю, что могу сделать грех нестатическим методом класса.Но тогда я теряю универсальность, потому что для любого другого числового объекта это sin (x) , а не x.sin () .

Добавление __ float __ неприемлем, так как я храню в объекте дополнительную информацию, такую ​​как производные для "автоматического дифференцирования".

TIA

Изменить: Если вам интересно, как выглядит код, проверьте this из. В идеальном мире я мог бы использовать sin / cos / sqrt в общем виде. Я считаю эти функции частью интерфейса объектов, даже если они являются «бесплатными функциями». В __ somefunction я не уточнял функции с помощью математики . ни __ основной __. . Это просто работает, потому что я вручную использую math.sin (и т.д.) в своих пользовательских функциях через декоратор. Но я считаю это уродливым взломом.

9
задан Donnied 22 April 2014 в 12:11
поделиться