Как сделать так, чтобы существующие функции в модуле math и numpy поддерживали определяемые пользователем объекты?

Я определил класс, который я хотел бы основные операции, такие как +, -и даже более сложные математические операции, такие как sin поддерживать. То есть мне нужно определить некоторые новые правила для этих основных операторов и математических функций.

Я мог бы иметь дело с базовыми операторами, используя магические методы Python, как показано ниже,

class NewObj():

    def __init__(self, *args):
        pass

    def __add__(self, other):
        pass

    def __mul__(self, other):
        pass

    # Use magic methods to define other basic operators below...

И я мог бы также переопределить основные функции в том же файле.py, где класс NewObj определяется, например,

def sin(x):
    pass

И назовите этот файл, скажем, myoperator.py. Тогда я мог бы импортировать этот модуль и применить новые операции на NewObj объекты.


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

Другой вопрос: возможно ли инкапсулировать функции внутри моего NewObj класс так же, как магические методы, так что все вещи написаны внутри структуры данных класса?

3 ответа

Решение

math Модуль явно документы, которые функционируют как math.sin всегда возвращайте поплавки. Если ты хочешь math.sin(your_object) вернуть NewObj экземпляр вместо floatне делай этого. Это может запутать всех, даже если вы заставите это работать, и это вызовет ошибки порядка инициализации и другие головные боли. (Есть причина, по которой у NumPy есть свои numpy.sin вместо того, чтобы пытаться сделать math.sin поддержка массивов NumPy.)

Если ты в порядке с math.sin(your_object) вернуть поплавок, затем реализовать __float__ метод для преобразования ваших объектов в поплавки:

class NewObj(object):
    ...
    def __float__(self):
        return whatever

math.sin преобразует ваш объект в число с плавающей точкой, вычисляет синус числа с плавающей точкой и возвращает синус как число с плавающей точкой.


Для NumPy просто внедрите sin метод:

class NewObj(object):
    ...
    def sin(self):
        return whatever

numpy.sin будет делегировать вашему sin метод. Вы можете вернуть NewObj; нет необходимости бросать, чтобы плавать или что-нибудь. Большинство похожих функций NumPy делегируют методы аналогичным образом. Тем не менее, попытка использовать пользовательские объекты внутри массивов NumPy сводит на нет большинство преимуществ эффективности NumPy, поэтому вы можете пересмотреть свой дизайн, если хотите это сделать.

Вы можете переопределить math модуля sin,

import math

class NewObj:
    pass

old_sin = math.sin

def new_sin(number):
    return 42.0 if isinstance(number, NewObj) else old_sin(number)

math.sin = new_sin

Предположительно вы замените 42.0 с еще более полезным определением.

Будем надеяться, что в не столь отдаленном будущем __numpy_ufunc__ специальный атрибут (имя может быть изменено). Вот соответствующий бит из версии dev от numy docs

class.__numpy_ufunc__(ufunc, method, i, inputs, **kwargs)

Новое в версии 1.11.

Любой класс (подкласс ndarray или нет) может определить этот метод, чтобы переопределить поведение ufuncs NumPy.

[акцент мой]

Другие вопросы по тегам