在Python 3中使用魔术方法计算欧几里得距离

时间:2018-09-18 13:29:03

标签: python oop

我有一个代码可以为我计算欧几里得距离:

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))

但是,现在我要使用__sub____pow__之类的python中的魔术方法来计算此距离。我已经成功实现了__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 :(得分:2)

如上所述,使用Point类表示向量可能不是一个好主意。在简单的程序中没关系,但是在更复杂的代码中可能会造成混淆。通常的做法是使积分不变。但是无论如何...

要执行此欧几里德距离运算,我们可以“滥用”新的__matmul__魔术方法。此方法由@运算符调用。这是一个基于您的代码的简短演示。请注意,我使用xy作为属性,没有充分的理由将它们标记为私有。

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)

输出

Point(7, 8)
Point(3, 4)
5.0

答案 1 :(得分:1)

将两个点的差作为一个点是没有意义的。看来您要实现的对象实际上是一个向量。

然后,该距离对应于用__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

答案 2 :(得分:0)

请注意,您对__pow__的定义对于矢量来说有点不规范。

但实际上,两个点p1p2的距离可以写为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__方法来简化自己的工作。

答案 3 :(得分:0)

您的二等班为我工作。我看不到任何问题:

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)

称其为向量或点或其他任何东西,似乎在执行您想要的操作。