Как я могу создать собственный тип данных в python, чтобы я мог перезаписать арифметические операторы?

В настоящее время я использую Python/Numpy для обработки географических/GPS-данных (любя его!), и я столкнулся с повторяющейся задачей расчета расстояний между географическими точками, определяемыми координатной парой pn = [lon, lat].

У меня есть функция, которую я использую следующим образом: dist = geodistance(p1, p2), аналог эвклидовому расстоянию в линейной алгебре (векторное вычитание/разность), но встречается в геодезическом (сферическом) пространстве вместо прямоугольного евклидова пространства.

Программно, эвклидово расстояние дается выражением

dist = ((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)**0.5

Математически это эквивалентно "идиоматическому" (из-за отсутствия лучшего слова) предложению

dist = p1 - p1 # the "norm" of the vector difference, subtraction.

В настоящее время я получаю свое расстояние следующим образом:

p1 = [-51.598354,-29.953363]
p2 = [-51.598701,-29.953045]
dist = geodistance(p1, p2)
print dist
>> 44.3904032407

Я хотел бы сделать это:

print p2 - p1 # these points now are from some fancy datatype
>> 44.3904032407

И конечная цель:

track = numpy.array([[-51.203018 -29.996149]
 [-51.203018 -29.99625 ]
 [-51.20266 -29.996229]
 [-51.20229 -29.996309]
 [-51.201519 -29.99416 ]], dtype=fancy) # (**) or something like
print numpy.diff(track)
>> ndarray([[ 0. ]
 [ 7.03531252]
 [ 39.82663316]
 [ 41.50958596]
 [ 172.49825765]])

Аналогично: если вы берете два объекта datetime и вычитаете их, операция возвращает объект timedelta. Я хочу вычесть две координаты и получить в результате геодезическое расстояние.

Интересно, будет ли класс работать, но dtype (например, "подтип" float32) мог бы помочь в создании массива из списков (это то, как я читаю вещи из xml файлов).

Спасибо большое!

2 ответа

Вы можете определить свои собственные типы, создав класс и назовите метод __add__ или __sub__.

Например:

class P(object):
 def __init__(self, lon, lat):
 self.lon = lon
 self.lat = lat
 def __sub__(self, other):
 dist = ((other.lon - self.lon)**2 + (other.lat - self.lat)**2)**0.5
 return dist

Учитывая, что вы в настоящее время получаете координаты своих точек, используя синтаксис индексации списка, вы также можете реализовать следующие:

class P(object):
 def __init__(self, lon, lat):
 self.lon = lon
 self.lat = lat
 def __sub__(self, other):
 dist = ((other[0] - self[0])**2 + (other[1] - self[1])**2)**0.5
 return dist
 def __getitem__(self, key):
 if key == 0:
 return self.lon
 elif key == 1:
 return self.lat
 else:
 raise IndexError
 def __setitem__(self, key, value):
 if key == 0:
 self.lon = value
 elif key == 1:
 self.lat = value
 else:
 raise IndexError

(Я понимаю, что вышеизложенное может быть не самым элегантным способом сделать это).

Таким образом, ваш новый класс является заменой для списков, которые вы в настоящее время используете.

Документация Python содержит дополнительную информацию о методах двойного подчеркивания, которые необходимо записать для создания ваших пользовательских типов. (Информация, которую вы ищете, начинается примерно на полпути вниз страницы)


Справочник по языку Python, §3.4.8, "Эмуляция числовых типов"

В частности, __sub__().

licensed under cc by-sa 3.0 with attribution.