我正在尝试实现以下目标:
我将空间集视为具有(几乎)相同方法的类:移动和旋转(这两种方法都会更新属性);检查某个点是否属于集合;等等
但是,在尝试实施补充时,我的问题出现了。我尝试了许多不同的方法,但不幸的是,没有一种方法效果很好。更糟糕的是,所有功能都有效的实现却显示出奇怪的副作用!
我将简要描述当前实施的内容:
让我分享一个简化版本的代码:
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
我猜Python只是动态地向类的对象添加新属性
Complementary
,方法是在调用显式初始化同一属性的方法时初始化它们。
请注意,.ispoint()
使用 center
属性,但是 .move_to()
显式初始化 center
(回想一下方法定义)。
所以,长话短说,我使用多重继承的方式导致了我不想要的巨大副作用。可能是由于
__init__
类的 Complementary
方法的非传统方式(我完全意识到这一点)。
我正在为我的问题寻求任何帮助。我确信继承可能不是一条出路。我脑海中的一些解决方案:
Complementary
类在这种情况下适合哪里。.complementary()
方法(在类Circle
和Bbox
中),该方法将支持“互补的互补”(双重否定)。感谢您的宝贵时间。
首先,你不想要多重继承。
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)