Перегрузка + для поддержки кортежей - PullRequest
5 голосов
/ 27 апреля 2011

Я бы хотел написать что-то подобное на python:

a = (1, 2)
b = (3, 4)
c = a + b # c would be (4, 6)
d = 3 * b # d would be (9, 12)

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

Конечно, такие решения, как

c = tuple([x+y for x, y in zip(a, b)])

работают, но, не говоря уже о производительности, они не так хороши, как перегрузка оператора +.

Конечно, можно определить функции add и mul, такие как

def add((x1, y1), (x2, y2)):
    return (x1 + x2, y1 + y2)

def mul(a, (x, y)):
    return (a * x, a * y)

но все же иметь возможность писать q * b + r вместо add(times(q, b), r) было бы лучше.

Идеи

РЕДАКТИРОВАТЬ : С другой стороны, я понимаю, что, поскольку + в настоящее время отображается на объединение кортежей, было бы неразумно переопределять его, даже если это возможно. Вопрос по-прежнему остается для -, например =)

Ответы [ 7 ]

6 голосов
/ 27 апреля 2011

В отличие от Ruby, вы не можете изменить поведение встроенных типов в Python. Все, что вы можете сделать, это создать новый тип производный из встроенного типа. Однако литералы по-прежнему будут создавать встроенный тип.

Наверное, лучшее, что вы можете получить, это

class T(tuple):
    def __add__(self, other):
        return T(x + y for x, y in zip(self, other))
    def __rmul__(self, other):
        return T(other * x for x in self)
a = T((1, 2))
b = T((3, 4))
c = a + b # c would be (4, 6)
d = 3 * b # d would be (9, 12)
3 голосов
/ 27 апреля 2011

Вы можете унаследовать класс от tuple и перегрузить его __add__ метод.Вот очень упрощенный пример:

class mytuple(tuple):
    def __add__(self, other):
        assert len(self) == len(other)
        return tuple([x + y for x, y in zip(self, other)])

mt = mytuple((5, 6))
print mt + (2, 3)  # prints (7, 9)

Я бы не рекомендовал этот подход, потому что кортежи не были специально разработаны для этой цели.Если вы хотите выполнить числовые вычисления, просто используйте numpy.

2 голосов
/ 27 апреля 2011

Есть известный оператор инфиксного хака , который позволил бы вам сделать что-то вроде этого:

x = Infix(lambda a,b:tuple([x+y for x, y in zip(a, b)]))
y = Infix(lambda a,b:tuple([a*y for y in b]))

c = a |x| b # c would be (4, 6)
d = 3 |y| b # d would be (9, 12) 

, который бы скрывал выражения генератора и был применим к кортежам любой длины,за счет "странных" псевдооператоров |x| и |y|.

2 голосов
/ 27 апреля 2011

Использование комплексных чисел Python, безусловно, является одним из способов сделать это, если не очень красивым.

a = 1 + 2j
b = 3 + 4j
c = a + b # c would be 4 + 6j
d = 3 * b # d would be 9 + 12j

Это сохраняет определение дополнительного класса.

Кроме того, расширение на предыдущие ответы

class T(tuple):
    def __add__((x, y), (x1, y1)):
        return T((x+x1, y+y1))
    def __rmul__((x, y), other):
        return T((other * x, other * y))

повысит производительность за счет ограничения реализации парами.

2 голосов
/ 27 апреля 2011

Вы не можете изменять типы, определенные в C, поэтому вам необходимо создать все новые типы для этого.Или вы можете просто использовать NumPy, который уже имеет типы, которые поддерживают это.

1 голос
/ 27 апреля 2011

Вы можете использовать numpy.array, чтобы получить все, что вам нужно.

1 голос
/ 27 апреля 2011

Напишите свой собственный класс и реализуйте __mul__, __add__ и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...