Python:重叠(非排他性)继承,使方法基于实例参数可用



我想有某些属性&方法仅在参数满足某些条件时在类实例中可用。不同的情况并不是相互排斥的。我已经有了一个可行的解决方案(包括shadowwranger的建议):

class polygon():
def __new__(cls, vert, axis=None):
triangle = vert == 3
solidrev = axis is not None
if triangle and not solidrev:
return super().__new__(_triangle)
elif solidrev and not triangle:
return super().__new__(_solid)
elif solidrev and triangle:
return super().__new__(_triangle_solid)
else:
return super().__new__(cls)
def __init__(self, vert, axis=None):
self.polygon_attribute = 1
def polygon_method(self):
print('polygon')
class _triangle(polygon):
def __init__(self, vert, axis=None):
super().__init__(vert, axis)
self.triangle_attribute = 2
def triangle_method(self):
print('triangle')
class _solid(polygon):
def __init__(self, vert, axis):
super().__init__(vert, axis)
self.solid_attribute = 3
def solid_method(self):
print('solid of revolution')
class _triangle_solid(_triangle, _solid):
def __init__(self, vert, axis):
super().__init__(vert, axis)

属性的可用性&方法取决于实例参数:

  • 属性&来自基类的方法应该始终可用。
  • 如果第一个参数等于3,属性&子类_triangle中的方法应该是可用的。
  • 如果定义了第二个参数,属性&子类_solid中的方法应该可用。
  • 所有组合

:

P = polygon(2)
P = polygon(2,axis=0)
P = polygon(3)
P = polygon(3,axis=0)

是否有更优雅的方法来做到这一点?在理想情况下,我想去掉_triangle_solid类。另外,我不明白为什么在某些情况下需要为axis定义默认参数,而不是所有情况。

完整项目:https://github.com/gerritnowald/polygon

这是一个试图过度使用继承的例子。继承在逻辑上是有意义的,当有"子类和父类之间的关系。三角形是多边形,所以没有问题;这是一个合理的继承链。旋转实体虽然可能由多边形构建,但不是多边形,试图将其嵌入继承层次结构会产生问题。更糟糕的是,旋转固体甚至可能根本不能用多边形来定义。

我强烈建议你用一个属性来定义你的旋转实体,这个属性表示任何被旋转的东西来产生它,而不是作为那个旋转图形的子类。


话虽如此,polygon本身不应该负责知道它的所有子类,如果它是,它仍然应该是三角形的父类。您的设计目前呈现有一个polygon类,nothing是一个实例;__new__返回的不是polygon,这很令人困惑。您可以使用一种更安全的(如果仍然不是惯用的)OO方式编写层次结构,方法如下:

# Tweaked name; it's not just the base anymore; using PEP8 class name capitalization rules
class Polygon:
def __new__(cls, vert, *args, **kwargs):  # Accept and ignore the arguments we don't care
# about, __init__ will handle them
if vert == 3:
return super().__new__(Triangle)
else:
return super().__new__(cls)
def __init__(self, vert, axis):
self.polygon_attribute = 1
def polygon_method(self):
print('polygon')
class Triangle(Polygon):
def __init__(self, vert, axis):
super().__init__(vert, axis)
self.triangle_attribute = 2
def triangle_method(self):
print('triangle')
t = Polygon(3, None)
p = Polygon(4, None)
print(type(t), type(p))
# Indicates t is a Triangle, p is a Polygon

上网试试!