Sympy(gometry子包)中发现的一个bug
- 问题来源:获取点到线段的距离。
- 点到线段的距离与点到直线的距离不同,点到线段的最短距离并不一定是垂直距离。但是当使用sympy.geometry.line中的Segmnet类创建实例化的线段,并使用Segment类中的 distance() 方法获取 某个点到这条线段的距离时,发现无论点在何处,计算的始终是点到直线的距离(即垂直距离)。
p1_sym = sympy.geometry.point.Point(1, 0)
p2_sym = sympy.geometry.point.Point(0, 1)
p3_sym = sympy.geometry.point.Point(10, 0)
s1_sym = sympy.geometry.line.Segment(p1_sym, p2_sym)
print(s1_sym.distance(p3_sym))
结果输出为 9*sqrt(2)/2,这显然是不对的。
- Debug后发现,调用distance() 方法,始终会跳至 Line 类中的distance() 方法,而不是 Segment 类中的 distance() 方法。究其原因,是因为Segment3D这个类继承了Segment, LinearEntity2D两个类,而 LinearEntity2D,有继承了Line类,最后就使用了Line 类中的distance() 方法。
sympy中Segment2D的继承
class Segment2D(LinearEntity2D, Segment):
将继承先后顺序修改,结果正确。继承顺序改为:
class Segment2D(Segment, LinearEntity2D):
看到这里,bug的原因找到了,是Python的多重继承问题引起的!!!
Python多重继承
新式类和经典类
- Python3 中全部默认是新式类,新式类和经典类的多重继承关系不同。在菱形继承(或称钻石继承)中,经典类多继承属性搜索顺序: 先深入继承树左侧,若没有搜索到,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动。
- 更多经典类和新式类的区别,请自行检索,但个人认为没必要纠结于二者的区别,新式类是未来,掌握新式类就完全OK。
继承关系
这里多重继承牵涉到的都是新式类。
1. 简单多重继承
class Line():
def distance(self):
print('value of A')
class LinearEntity(Line):
pass
class Segment():
def distance(self):
print('value of C')
class Segment2D(LinearEntity, Segment):
pass
test = Segment2D()
test.distance()
打印结果 : value of A
更改Segment2D类对父类的继承顺序:
class Line():
def distance(self):
print('value of A')
class LinearEntity(Line):
pass
class Segment():
def distance(self):
print('value of C')
class Segment2D(Segment, LinearEntity):
pass
test = Segment2D()
test.distance()
打印结果 : value of c
结论:简单多重继承,先一直深入搜索左边,没有找到相关属性/方法,再搜索右边
2. 菱形继承
当一个子类继承2个父类,而2个父类又都继承一个基类,构成了一个菱形.
为验证菱形继承的继承关系,修改上面的代码,如下:
class Line():
def distance(self):
print('value of A')
class LinearEntity(Line):
pass
class Segment(Line):
def distance(self):
print('value of C')
class Segment2D(LinearEntity, Segment):
pass
test = Segment2D()
test.distance()
打印结果 : value of c
更改Segment2D类对父类的继承顺序:
class Line():
def distance(self):
print('value of A')
class LinearEntity(Line):
pass
class Segment():
def distance(self):
print('value of C')
class Segment2D(Segment, LinearEntity):
pass
test = Segment2D()
test.distance()
打印结果 : value of c
可以看到,不管继承先后,菱形继承关系中,都是先左右搜索,再上下搜索,即一层一层搜索。