Переопределяющие операторы внутри функций - PullRequest
2 голосов
/ 25 февраля 2012

Я хочу определить операторы для экземпляра класса внутри функции класса, например:

class MyClass(object):

    @property
    def _arithmetic_threshold(self):
        return self.threshold # this will be defined somewhere

    @_arithmetic_threshold.setter
    def _arithmetic_threshold(self,value):
        self.threshold = value
        self._define_arithmetic_attributes()

    def _define_arithmetic_attributes(self):
        """
        Wrapper to define all arithmetic attributes (in order to allow threshold changes)
        """

        self.__add__ = self._operation_wrapper(np.add,threshold=self._arithmetic_threshold)
        self.__sub__ = self._operation_wrapper(np.subtract,threshold=self._arithmetic_threshold)
        self.__mul__ = self._operation_wrapper(np.multiply,threshold=self._arithmetic_threshold)
        self.__div__ = self._operation_wrapper(np.divide,threshold=self._arithmetic_threshold)

Однако, похоже, это не работает - я чувствую, что мне чего-то не хватает в том, как операторы -, + и т. Д. Вызывают эти функции. i.e.:

class MyClass2(object):
    def __add__(self,other,threshold=None):
        if threshold is not None:
            return self+other
        else:
            # do something here involving checking a threshold....
            pass

в MyClass2 поведение __add__ будет другим. Может кто-нибудь объяснить, чем они отличаются, и как сделать поведение методов оператора в MyClass похожим на MyClass2?

РЕДАКТИРОВАТЬ: Просто чтобы прояснить, почему я пытаюсь сделать это, вот _operation_wrapper. Класс, для которого это метод, является объектом «Спектр», который имеет ось X и ось Y. Цель состоит в том, чтобы разрешить арифметику по осям Y, но только если оси X совпадают. Однако для них допустимо совпадать, скажем, с 1/5 размера пикселя, поэтому я хотел сделать больше, чем просто «точное» сопоставление.

def _operation_wrapper(operation):
    """
    Perform an operation (addition, subtraction, mutiplication, division, etc.)
    after checking for shape matching
    """

    def ofunc(self, other): 
        if np.isscalar(other):
            newspec = self.copy()
            newspec.data = operation(newspec.data, other) 
            return newspec
        else: # purely for readability

            if self._arithmetic_threshold == 'exact':
                xarrcheck = all(self.xarr == other.xarr)
            else:
                if self._arithmetic_threshold_units is None:
                    # not sure this should ever be allowed
                    xarrcheck = all((self.xarr-other.xarr) < self._arithmetic_threshold)
                else:
                    xarrcheck = all((self.xarr.as_unit(self._arithmetic_threshold_units)-other.xarr.as_unit(self._arithmetic_threshold_units)) < self._arithmetic_threshold)

            if self.shape == other.shape and xarrcheck:
                newspec = self.copy()
                newspec.data = operation(newspec.data, other.data)
                return newspec
            elif self.shape != other.shape:
                raise ValueError("Shape mismatch in data")
            elif not xarrcheck:
                raise ValueError("X-axes do not match.")

    return ofunc

1 Ответ

6 голосов
/ 25 февраля 2012

Специальные методы, такие как __add__(), ищутся для типа объекта, а не для экземпляра. Так

a + b

примерно переводится как

type(a).__add__(a, b)

Это означает, что установка __add__ в экземпляре не делает ничего полезного (кроме работы a.__add__(b)).

Ваш пример немного неполон, поэтому я не могу предоставить полный рабочий код. Вы можете переместить код из _define_arithmetic_attributes() в тело класса и получить доступ к self.threshold изнутри operation_wrapper().

(Обратите внимание, что я не понимаю смысл свойства _arithmetic_threshold. Почему бы вам просто не получить доступ к самому self.threshold?)

...