Расчет евклидова расстояния с использованием магических методов в Python 3 - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть код, который вычисляет евклидово расстояние для меня:

class Point:
    """A point in two-dimensional space."""

    def __init__(self, x, y):
        self._x = x
        self._y = y

    def __eq__(self, other):
        return self._x == other._x and self._y == other._y

    def distance(self, other):
        new_x = self._x - other._x
        new_y = self._y - other._y
        print(new_x,'  ',new_y)
        return (new_x ** 2 + new_y ** 2) ** 0.5

p1 = Point(10, 4)
p2 = Point(3, 1)


print('Euclidean distance : 'p1.distance(p2))

Однако теперь я хочу вычислить это расстояние, используя магические методы в Python, такие как __sub__ и __pow__. Мне удалось реализовать __sub__, но я не знаю, как реализовать для __pow__ и квадратный корень. Это мой код:

class Point_1(object):

    def __init__(self, x, y):
        self._x = x
        self._y = y


    def setX(self, x,y):
        self._x = x
        self._y = y

    def getX(self):
        return self._x,self._y


    def __sub__ (self, other ):
        return Point_1(self._x - other._x, self._y - other._y)

    def __pow__(self,p):
        return Point_1(self._x ** p, self._y **p)




p1 = Point_1(10,4)
print(p1.getX())

p2 = Point_1(3,1)
print(p2.getX())

p3 = p1 - p2

Как я могу реализовать остальную часть формулы, используя магические методы. Я действительно смущен. Помочь бы мне оценили.

Ответы [ 4 ]

0 голосов
/ 18 сентября 2018

Как уже упоминалось, может быть не очень хорошая идея использовать класс Point для представления векторов.Это нормально в простых программах, но это может запутать в более сложном коде.Обычная практика - делать точки неизменными.Но в любом случае ...

Чтобы выполнить эту евклидову дистанционную операцию, мы можем "злоупотребить" новым магическим методом __matmul__.Этот метод вызывается оператором @.Вот короткая демонстрация на основе вашего кода.Обратите внимание, что я использую x и y в качестве атрибутов, нет веских оснований помечать их как частные.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return "Point({}, {})".format(self.x, self.y)

    def __add__ (self, other ):
        return Point(self.x + other.x, self.y + other.y)

    def __sub__ (self, other ):
        return Point(self.x - other.x, self.y - other.y)

    def __pow__(self, p):
        return Point(self.x ** p, self.y **p)

    def __abs__(self):
        d = self ** 2
        return (d.x + d.y) ** 0.5

    def __matmul__(self, other):
        ''' Euclidean distance between self & other '''
        return abs(self - other)

# Test

a = Point(5, 6)
b = Point(2, 2)
print(a + b)
print(a - b)
print(a @ b)

output

Point(7, 8)
Point(3, 4)
5.0
0 голосов
/ 18 сентября 2018

Не имеет смысла, чтобы разница двух точек была точкой.Кажется, объект, который вы пытаетесь реализовать, на самом деле является вектором.

Тогда расстояние соответствует норме вектора, реализованной с помощью __abs__.

class Vector:
    def __init__(self, *args):
        self._coords = args

    def __add__(self, other):
        return Vector(*[x + y for x, y in zip(self._coords, other._coords)])

    def __sub__(self, other):
        return Vector(*[x - y for x, y in zip(self._coords, other._coords)])

    def __abs__(self):
        """Euclidian norm of the vector"""
        return sum(x**2 for x in self._coords) ** (1 / 2)

Пример

v1 = Vector(1, 3)
v2 = Vector(4, -1)

print(abs(v2 - v1)) # 5.0

# Also works in higher dimensions
v3 = Vector(1, -1, 0)
v4 = Vector(4, 6, -2)

print(abs(v3 - v4)) # 7.87
0 голосов
/ 18 сентября 2018

Ваш второй класс работает на меня.Я не вижу никаких проблем с ним:

In [9]: class Point_1(object):
   ...:     
   ...:     def __init__(self, x, y):
   ...:         self._x = x
   ...:         self._y = y
   ...:   
   ...:     
   ...:     def setX(self, x,y):
   ...:         self._x = x
   ...:         self._y = y
   ...:  
   ...:     def getX(self):
   ...:         return self._x,self._y
   ...:     
   ...:     
   ...:     def __sub__ (self, other ):
   ...:         return Point_1(self._x - other._x, self._y - other._y)
   ...:     
   ...:     def __pow__(self,p):
   ...:         return Point_1(self._x ** p, self._y **p)

А затем:

In [14]: p1 = Point_1(10,4)
    ...: print(p1.getX())
    ...: 
    ...: p2 = Point_1(3,1)
    ...: print(p2.getX())
    ...: 
    ...: p3 = p1 - p2
    ...: 
    ...: 
(10, 4)
(3, 1)

In [15]: p3.getX()
Out[15]: (7, 3)

Назовите это вектором или точкой или чем-то еще, кажется, что вы делаете то, что хотите.

0 голосов
/ 18 сентября 2018

Обратите внимание, что ваше определение __pow__ немного нестандартно для векторов.

Но на самом деле расстояние между двумя точками p1 и p2 можно записать как sum((p1 - p2)**2)**.5.Поэтому нам нужен ваш __pow__ метод, ваш __sub__ метод, и единственным другим дополнением является __iter__ метод, который позволяет sum работать:

class Point:
    """A point in two-dimensional space."""

    def __init__(self, x, y):
        self._x = x
        self._y = y

    def __eq__(self, other):
        return self._x == other._x and self._y == other._y

    def __sub__(self, other):
        return Point(self._x - other._x, self._y - other._y)

    def __pow__(self, power):
        return Point(self._x**power, self._y**power)

    def __iter__(self):
        yield self._x
        yield self._y

    def distance(self, other):
        return sum((self - other)**2)**.5

p1 = Point(2, 3)
p2 = Point(5, -1)

print(p1.distance(p2))
Out: 5.0

Это самый короткий путь, основанный на вашемсуществующий код в любом случае.Вы можете поэкспериментировать дальше, добавив метод скалярного умножения и метод сложения, а затем определив sub как p1 + (-1)*p2.Вы также можете упростить себе задачу, внедрив метод __repr__.

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