python sum() и нецелочисленные значения

Есть ли простой и быстрый способ использовать sum() с нецелыми значениями?

Поэтому я могу использовать его так:

class Foo(object):
    def __init__(self,bar)
        self.bar=bar

mylist=[Foo(3),Foo(34),Foo(63),200]
result=sum(mylist) # result should be 300

Я пытался переопределить __add__ и __int__ и т. д., но пока не нашел решения.

ИЗМЕНИТЬ:

Решение заключается в реализации:

 def __radd__(self, other):
    return other + self.bar

как предложил Уилл в своем посте. Но как всегда все дороги ведут в Рим, но думаю это лучшее решение так как __add__ в моем классе не нужно


person sloth    schedule 02.08.2009    source источник


Ответы (6)


Это немного сложно - функция sum() берет начало и добавляет его к следующему и так далее.

Вам нужно реализовать метод __radd__:

class T:
    def __init__(self,x):
        self.x = x
    def __radd__(self, other):
        return other + self.x

test = (T(1),T(2),T(3),200)
print sum(test)
person Will    schedule 02.08.2009
comment
Если вы хотите использовать любой другой тип, кроме int, вы можете использовать sum(test, start=T(0)), иначе вы получите ошибку TypeError: unsupported operand type(s) for +: 'int' and 'str' - person Max; 05.03.2021

Вам также может понадобиться реализовать функцию __radd__, которая представляет «обратное добавление» и вызывается, когда аргументы не могут быть разрешены в «прямом» направлении. Например, x + y оценивается как x.__add__(y), если это возможно, но если этого не существует, Python пытается использовать y.__radd__(x).

Поскольку функция sum() начинается с целого числа 0, первое, что она делает, это пытается вычислить:

0 + Foo(3)

что потребует от вас реализации Foo.__radd__.

person Greg Hewgill    schedule 02.08.2009
comment
Знание учета 0 было чрезвычайно полезно для моего случая использования, когда я создаю сложную структуру данных, которая комбинируется сама с собой посредством сложения. Большое спасибо за обстоятельный ответ! - person Craig Labenz; 10.03.2019

Пытаться:

import operator
result=reduce(operator.add, mylist)

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

class Foo(object):
    def __init__(self, i): self.i = i
    def __add__(self, other):
        if isinstance(other, int):
            return Foo(self.i + other)
        return Foo(self.i + other.i)
    def __radd__(self, other):
        return self.__add__(other)

import operator
mylist = [Foo(42), Foo(36), Foo(12), 177, Foo(11)]
print reduce(operator.add, mylist).i
person liori    schedule 02.08.2009
comment
из functools импортировать уменьшить # Py3 - person Gringo Suave; 10.11.2016
comment
Это наиболее универсальное решение, которое работает для любого типа, реализующего __add__, включая те, которые не предназначены для работы с sum(...), например количества с единицами измерения в библиотеке pint. - person gerrit; 20.06.2017

Попробуйте использовать метод __int__, а затем сопоставьте каждый элемент в вашем списке с функцией int, чтобы получить значения:

class Foo(object):
    def __init__(self,bar):
        self.bar = bar
    def __int__(self):
        return self.bar

mylist = [Foo(3),Foo(34),Foo(63),200]
result = sum(map(int,mylist))
print(result)
person Andrew Hare    schedule 02.08.2009

Или, если вы не хотите ничего импортировать,

result = reduce((lambda x,y:x+y), mylist)

Еще одно небольшое преимущество заключается в том, что вам не нужно обязательно объявлять метод __add__ как часть ваших объектов Foo, если это единственное обстоятельство, в котором вы хотите выполнить сложение. (Но, вероятно, не помешало бы определить __add__ для гибкости в будущем.)

person Amber    schedule 02.08.2009
comment
У этого есть тонкая проблема: если список содержит только один элемент, то (лямбда x, y: x + y) никогда не будет вызываться, и сокращение вернет этот единственный элемент. Если этот единственный элемент является объектом, а не целым числом, результатом будет объект, а не сумма. - person mercury0114; 31.10.2020

sum() (без целочисленного хака) решение кажется самым чистым; поскольку sum() начинается с нуля, обработайте этот случай (из http://www.marinamele.com/2014/04/modifying-add-method-of-python-class.html):

def __radd__(self, other):
    if other == 0:
        return self
    else:
        return other.__add__(self)
person Lofty Lion    schedule 01.05.2020