Sympy的一个Bug,牵涉到Python多重继承问题

本文探讨了Sympy中一个关于点到线段距离计算的bug,该bug源于多重继承导致的方法调用错误。通过调整继承顺序解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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() 方法。
sympySegment2D的继承
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

可以看到,不管继承先后,菱形继承关系中,都是先左右搜索,再上下搜索,即一层一层搜索。

文末语:文章大部分还是在自己的博客网站上发布,更多内容可移步我的个人网站 《浮生,奈若何》,www.linzhongya.top

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值