gpt4 book ai didi

python - 用不同的 __new__ 签名为 child 实例化 __new__ 中的 child

转载 作者:太空狗 更新时间:2023-10-30 00:00:50 26 4
gpt4 key购买 nike

前言

我想要具有以下属性的 2 个类 IntervalSegment:

  1. Interval 可以有 startend 点,它们中的任何一个都可以被包含/排除(我已经使用必需的标志参数实现了这个像 start_inclusive/end_inclusive)。
  2. Segment 是一个包含两个端点的Interval,因此用户不需要指定这些标志。
  3. 如果用户尝试创建包含端点的Interval,他会得到一个Segment,如

    >>> Interval(0, 1, start_inclusive=True, end_inclusive=True)
    Segment(0, 1)

    ( this doesn't look impossible )

问题

我的 MCVE到目前为止的实现是

区间类:

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

类:

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__ “绑定(bind)”的一些参数来实例化子类一个 child ?

最佳答案

让我们先看看为什么会出现错误。当您调用派生自 object 的类时, __call__ metaclass 的方法( type ) 被调用。这通常是这样的

self = cls.__new__(...)
if isinstance(self, cls):
type(self).__init__(self)

这只是近似值,但足以传达这里发生的事情:

  1. type.__call__ 调用 Interval.__new__
  2. 由于 start_inclusive 和 end_inclusiveInterval.__new__ 正确返回了 Segment
  3. 的实例
  4. 由于 issubclass(Segment, Interval)type.__call__ 使用您传递给调用的所有参数调用 Segment.__init__间隔
  5. Segment.__init__ 不接受任何关键字参数,并引发您看到的错误。

对于这种情况,有许多解决方法。 @jdehesa's answer显示如何覆盖 type 的行为,以便 type.__call__ 检查 type(obj) is cls 而不是使用 isinstance.

另一种选择是分离IntervalSegment 的层次结构。你可以做类似的事情

class MyBase:
# put common functionality here

class Interval(MyBase):
# __new__ and __init__ same as before

class Segment(MyBase):
# __new__ and __init__ same as before

通过这种安排,isinstance(Segment(...), Interval) 将为 False,而 type.__call__ 将为 不要尝试在Segment 上调用Interval.__init__

在我看来,最简单的方法是使用工厂模式。有一个外部函数,可以根据输入确定返回什么类型的对象。这样一来,你根本不需要实现__new__,你的类构建过程也会简单很多:

def factory(start, end, *, start_inclusive, end_inclusive):
if start_inclusive and end_inclusive:
return Segment(start, end)
return Interval(start, end, start_inclusive=start_inclusive, end_inclusive=end_inclusive)

关于python - 用不同的 __new__ 签名为 child 实例化 __new__ 中的 child ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57078848/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com