【发布时间】:2019-11-26 11:08:53
【问题描述】:
前言
我想要 2 个类 Interval 和 Segment 具有以下属性:
-
Interval可以有start和end点,它们中的任何一个都可以包含/排除(我已经使用必需的标志参数实现了这一点,例如start_inclusive/end_inclusive)。 -
Segment是一个包含两个端点的Interval,因此用户不需要指定这些标志。 -
如果用户尝试创建包含端点的
Interval,他会得到Segment之类的>>> Interval(0, 1, start_inclusive=True, end_inclusive=True) Segment(0, 1)
问题
到目前为止,我的MCVE 实现是
Interval类:
class Interval:
def __new__(cls, start: int, end: int,
*,
start_inclusive: bool,
end_inclusive: bool) -> 'Interval':
if cls is not __class__:
return super().__new__(cls)
if start == end:
raise ValueError('Degenerate interval found.')
if start_inclusive and end_inclusive:
return Segment(start, end)
return super().__new__(cls)
def __init__(self,
start: int,
end: int,
*,
start_inclusive: bool,
end_inclusive: bool) -> None:
self.start = start
self.end = end
self.start_inclusive = start_inclusive
self.end_inclusive = end_inclusive
Segment类:
class Segment(Interval):
def __new__(cls, start: int, end: int) -> 'Interval':
return super().__new__(cls, start, end,
start_inclusive=True,
end_inclusive=True)
def __init__(self, start: int, end: int) -> None:
super().__init__(start, end,
start_inclusive=True,
end_inclusive=True)
创作有点效果
>>> Interval(0, 1, start_inclusive=False, end_inclusive=True)
<__main__.Interval object at ...>
>>> Interval(0, 1, start_inclusive=False, end_inclusive=False)
<__main__.Interval object at ...>
>>> Segment(0, 1)
<__main__.Segment object at ...>
但是
>>> Interval(0, 1, start_inclusive=True, end_inclusive=True)
未能关注TypeError
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'end_inclusive'
所以我的问题是:
是否有任何惯用的方式在父级的 __new__ 中实例化子类,其中一些参数为 __new__ 和 __init__ “绑定”子级?
【问题讨论】:
-
您是否有理由不希望用户只选择他们想要的类?另外,您在区间中没有任何特殊功能吗?
-
@MadPhysicist:对这两个问题都是肯定的,检查点是否在段中会更快(我已经测量过了,是的,由于检查和间隔的数量,这个小改进确实很重要)因为我在检查端点时不需要找出使用哪个运算符
<或<=,因为它将是<=,但从我的角度来看问题更普遍 -
Segment 和 Interval 似乎完全不同的想法,即使它们具有共同的功能。如果它们可以共享一个通用的抽象基类,而不是在层次结构中排列,那么两个想法都会更好地表达,并且您的实例化会更简单?
-
这个设计在我看来很可疑。你到底想用代码的
if cls is not __class__:部分做什么? -
基本上,当
__new__返回Segment时,Segment仍然是Interval的子类,因此它会尝试在结果上调用type(obj).__init__(obj)。但是obj在其__init__中缺少两个关键字参数。
标签: python python-3.x oop inheritance