我希望有两个类Interval
和Segment
具有以下属性:
Interval
可以有start
&;end
点,它们中的任何一个都可以被包含/排除(我已经使用所需的标志参数,如start_inclusive
/end_inclusive
)来实现这一点。在Segment
是一个包含两个端点的{如果用户试图创建包含端点的Interval
,他将得到一个Segment
的
>>> Interval(0, 1, start_inclusive=True, end_inclusive=True)
Segment(0, 1)
到目前为止,我的MCVE实现是
Interval
类:
Segment
类:
创造有点管用
>>> 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__
“绑定”的子类?
让我们先看看为什么会出现错误。当您调用从^{} 派生的类时,metaclass(^{} )的^{} 方法被调用。通常是这样的
这仅仅是一个近似值,但足以传达出这里正在发生的事情:
type.__call__
调用^{start_inclusive and end_inclusive
,Interval.__new__
正确返回Segment
的实例issubclass(Segment, Interval)
,type.__call__
调用Segment.__init__
,其中包含您传递给Interval
调用的所有参数Segment.__init__
不接受任何关键字参数,并引发您看到的错误。在对于这种情况有很多解决办法。@jdehesa's answer演示如何重写{}的行为,以便},而不是使用
type.__call__
检查{isinstance
。在另一种选择是分离}的层次结构。你可以做些像
^{pr2}$Interval
和{在这种安排下,}将不尝试在
isinstance(Segment(...), Interval)
将是False
,而{Segment
上调用Interval.__init__
。在在我看来,最简单的方法就是使用工厂模式。有一个外部函数,根据输入确定要返回的对象类型。这样,您根本不需要实现
__new__
,并且您的类构造过程将更加简单:当在
__new__
之后调用__init__
时,可以使用一个要自定义的元类来解决这个问题:相关问题 更多 >
编程相关推荐