Могу ли я изменить значение базового класса в подклассе Python?

1

При подклассификации базового типа, такого как float, можно ли "пересчитать" или "переназначить" исходное значение? Если у меня есть следующее определение класса,

import collections

class MovingAverage(float):
    def __new__(self, initial_value, window):
        self.d = collections.deque([initial_value], window)
        return float.__new__(self, initial_value)
    def add(self, new_value):
        self.d.append(new_value)
        print sum(self.d) / len(self.d)
        # here, I want to _set_ the value of MovingAverage to
        #     sum(self.d) / len(self.d)

Когда я начинаю с

>>> ma = MovingAverage(10, 3)
>>> ma
10.0

но

>>> ma.add(3)
6.5
>>> ma
10.0

Другое определение класса, которое я пробовал, следующее:

import collections

class MovingAverage(float):
    def __new__(self, iterable, window):
        self.d = collections.deque(iterable, window)
        initial_value = sum(iterable) / len(iterable)
        return float.__new__(self, initial_value)
    def add(self, new_value):
        self.d.append(new_value)
        return MovingAverage(self.d, self.d.maxlen)

На этот раз, когда я начну с

>>> ma = MovingAverage([10], 3)
>>> ma
10.0

а также

>>> ma.add(3)
6.5
>>> ma
10.0
>>> ma = ma.add(3)
>>> ma
5.333333333333333

Однако, я думаю (я не проверял, чтобы узнать), это делает это значительно медленнее. Итак, можно ли это сделать? Могу ли я как-то установить его так, чтобы возвращение от ma было значением, которое я ищу? Или мне нужно определить атрибут value, изменить базовый класс на object и отказаться от моего предлога, что у меня есть возможность контролировать возвращаемое значение класса?

  • 0
    подклассы из числа с плавающей точкой для скользящего среднего ПЛОХО
  • 0
    Я не думаю, что когда-либо видел случай, когда на самом деле хорошей идеей является создание подкласса числового типа в Python.
Теги:
subclass

2 ответа

5
Лучший ответ

Нет. Поскольку эти типы неизменяемы, вы должны использовать инкапсуляцию, а не наследование.

2

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

class MovingAverage:
    def __init__(self):
        self.sum = None
        self.num = 0

    def add(self, val):
        if self.sum is None:
            self.sum = val
        else:
            self.sum += val
        self.num += 1
        return self.val

    @property
    def val(self):
        if self.sum is None:
            return None
        else:
            return self.sum/self.num

if __name__ == "__main__":
    print("Running small test suite")
    fail = False

    m = MovingAverage()
    try:
        assert m.val is None, "A new MovingAverage should be None"
        assert m.add(10) == 10, "New average should be returned"
        assert m.val == 10, "The average should update for each add"
        assert m.add(20) == 15, "New average should be returned"
        assert m.val == 15, "The average should update for each add"
        assert m.add(0) == 10, "Adding zero should work"
        assert m.add(-10) == 5, "Adding a negative number should work"
        assert m.add(-1) == 19/5, "Result should be able to be a fraction"
    except AssertionError as e:
        print("Fail: %s" % e.args[0])
        fail = True

    if not fail: print("Pass")
  • 0
    Спасибо, я могу использовать это (ну, что-то вроде этого) для того, что я пытаюсь сделать. Твоя не скользящая средняя, а скорее скользящая средняя. Я мог бы придерживаться deque, чтобы ограничить итог окном значений.
  • 0
    Извините, это правда :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню