多重继承:如何正确重写方法?物体的互补性的互补性

问题描述 投票:0回答:1

TL;博士

  • 我正在尝试实现空间区域的互补的互补
  • 当前的解决方案具有巨大的副作用
  • 该解决方案基于多重继承。这不遵循最佳实践
  • 对于我的用例来说,由于副作用,多重继承可能不是可行的方法
  • 我正在寻求帮助/建议,这将向我指出另一种方法(抽象类、模式匹配等)

详细

我正在尝试实现以下目标:

  • 考虑空间集,例如圆形和矩形。它们占据的区域由各自的方程定义
  • 还要考虑这些集合的互补性。他们的区域是整个宇宙,除了“原始”集合定义的“洞”
  • 而且,补数的补数就是集合本身
  • 空间集不是静态的,它们可以移动(始终保持其形状)。在互补的情况下,这没有多大意义,我并不真正需要这个功能来实现我的目的

我将空间集视为具有(几乎)相同方法的类:移动和旋转(这两种方法都会更新属性);检查某个点是否属于集合;等等

但是,在尝试实施补充时,我的问题出现了。我尝试了许多不同的方法,但不幸的是,没有一种方法效果很好。更糟糕的是,所有功能都有效的实现却显示出奇怪的副作用!

我将简要描述当前实施的内容:

  1. 定义不同的类(圆形、矩形等)
  2. 定义Complementary类,它是上面提到的类(多重继承)的子类,该类与前面的类唯一的区别是对各自空间集占用的区域取反

让我分享一个简化版本的代码:

class Bbox:
    def __init__(self,cm,w,h):
        self.cm = cm # center of mass
        self.w  = w # bbox width
        self.h  = h # bbox height
        # more stuff here to initialize
        # doesn't matter now
    
    def move_to(self,xy):
        # upd center of mass to point xy
        self.cm = xy

    def rotate(self,alpha):
        # rotate the bounding box (upd the vertices positions)
        # doesn't matter now
        pass

    def ispoint(self,xy):
        # checks if xy point belongs to the bounding box
        
        # For simplicity sake I'll just override the
        # original auxiliary functions of this method
        # with the boolean value True
        return True

class Circle:
    def __init__(self,center,radius):
        self.center = center
        self.radius = radius

    def move_to(self,xy):
        # upd center to point xy
        self.center = xy

    def ispoint(self,xy):
        # check if xy point belongs to the circle
        xy_isinside = (xy[0]-self.center[0])**2 + (xy[1]-   self.center[1])**2 <= self.radius**2
        return xy_isinside

class Complementary(Circle,Bbox):
    # almost sure that the root cause of my problem
    # is the way I'm defining the constructor
    # I've tried many alternatives and this
    # one works ALMOST fine. More on this later
    def __init__(self, term):
        self.term = term
        # this is not the best way the constructors
        # in multiple inheritance are defined

    def ispoint(self,xy):
        # this is the main thing I want
        # I want to negate the region of the term
        # whether this term is the "original" one
        # or the term is already a complementary
        return not self.term.is_point_in(xy)
        # NOTE: I cannot use .super() here, because
        # it doesn't work in the "second" complementary
        # because will always negate the parent's method

## Tests ##
# circle with center (0,0) and radius 1
circ = Circle([0,0],1)
# complementary of the circle (whole universe with circ as the "hole")
circ_c  = Complementary(circ)
# complementary of the complementary: equivalent to the circ itself
circ_cc = Complementary(circ_c)

# bounding box with center (0,0) and width=2,height=4
bb = Bbox([0,0],2,4)
# complementary of the bbox
bb_c = Complementary(bb)
# complementary of the complementary: equivalent to the bbox itself
bb_cc = Complementary(bb_c)

# Test .ispoint() method #
print(f"is (0,0) in circ {circ.ispoint([0,0])}") # must be true
print(f"is (0,0) in circ_c {circ_c.ispoint([0,0])}") # must be false
print(f"is (0,0) in circ_cc {circ_cc.ispoint([0,0])};") # must be true
# working as intended

print(f"is (1,2) in bb {bb.ispoint([1,2])}") # must be true
print(f"is (1,2) in bb_c {bb_c.ispoint([1,2])}") # must be false
print(f"is (1,2) in bb_cc {bb_cc.ispoint([1,2])};") # must be true
# working as intended
# NOTE that Python is picking the "correct" .ispoint() method,
# the one respective to the Bbox class

现在,当我尝试调用

Complementary
对象的属性时,问题就出现了。举个例子:尝试调用
circ_c.center
,它会抛出一个错误,指出
circ_c
没有这样的属性。 但是,如果first调用
.move_to()
方法,then获取属性,它就可以正常工作了:

circ_c.center
circ_c.move_to([0,0])
circ_c.center

printscreen of the error

我猜Python只是动态地向类的对象添加新属性

Complementary
,方法是在调用显式初始化同一属性的方法时初始化它们。 请注意,
.ispoint()
使用
center
属性,但是
.move_to()
显式初始化
center
(回想一下方法定义)。

所以,长话短说,我使用多重继承的方式导致了我不想要的巨大副作用。可能是由于

__init__
类的
Complementary
方法的非传统方式(我完全意识到这一点)。

我正在为我的问题寻求任何帮助。我确信继承可能不是一条出路。我脑海中的一些解决方案:

  1. 一位朋友建议使用模式匹配(一种更实用的方法),但是这个建议太模糊了,我无法理解它。
  2. 使用抽象类,这对我来说似乎很有希望。但是,我不清楚
    Complementary
    类在这种情况下适合哪里。
  3. 以某种方式使用与抽象类的模式匹配
  4. 以某种方式实现一个
    .complementary()
    方法(在类
    Circle
    Bbox
    中),该方法将支持“互补的互补”(双重否定)。

感谢您的宝贵时间。

python-3.x oop pattern-matching abstract-class multiple-inheritance
1个回答
0
投票

首先,你不想要多重继承。

Complementary
区域不能同时是
Circle
BBox
!如果有的话,您应该定义一个
class ComplementaryCircle(Circle)
和第二个
class ComplementaryBBox(BBox)

但是,考虑到您的使用情况

# complementary of the circle (whole universe with circ as the "hole")
circ_c  = Complementary(circ)

你真正想要的是使用装饰器模式。装饰器类是一个包装器,它既不是

Circle
也不是
BBox
的子类,尽管它确实实现了与它们相同的接口。所以这只是

class Complementary:
    def __init__(self, term):
        self.term = term

    def move_to(self, xy):
        self.term.move_to(xy)
    def rotate(self, alpha):
        self.term.rotate(alpha)

    def is_point_in(self,xy):
        return not self.term.is_point_in(xy)
© www.soinside.com 2019 - 2024. All rights reserved.