我有一个类“ A”,它具有子类“ B”,“ C”和D。 “ A”仅用于分类和继承,因此我不希望用户创建“ A”的实例。 但是,我想照常创建“ B”,“ C”和“ D”的实例。
首先,我通过覆盖A.__new__
来阻止'A'实例的生成。
然后,我再次覆盖B.__new__
,如下所示。
class A(object):
def __new__(cls, *args, **kwargs):
raise AssertionError('A cannot be generated directly.')
class B(A):
def __new__(cls, *args, **kwargs):
return super(cls,B).__new__(cls, *args, **kwargs)
但是,使用此代码,生成B会返回相同的AssertionError。
我了解到,由于A.__new__
被禁用,super(cls,B).__new__
(与A.__new__
完全相同)也被禁用。
有什么方法可以生成子类的实例,而无需调用其超类的__new__
?
我没有调用A.__new__
,而是调用了更高超类(即“对象”)的__new__
方法。此解决方案避免了这个问题。
新代码如下:
class A(object):
def __new__(cls, *args, **kwargs):
raise AssertionError('A cannot be generated directly.')
class B(A):
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
请注意,它是return object.__new__(cls)
,而不是return object.__new__(cls, *args, **kwargs)
。这是因为object.__new__
除了cls
之外没有其他参数,因此不必传递任何参数。
答案 0 :(得分:1)
您正在A.__new__
方法中显式调用B.__new__
。这个版本运作良好:
class A:
def __new__(cls, *args, **kwargs):
raise AssertionError()
class B(A):
def __new__(cls, *args, **kwargs):
pass
结果:
>>> x = A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __new__
AssertionError
>>> y = B()
>>> y
>>>
请注意,B.__new__
现在几乎没有用:我实际上没有得到B
实例(y
为空)。我假设您有实际的理由要修改__new__
,在这种情况下,请将替换代码放在我有pass
的位置。
如果您不要有充分的理由修改__new__
,请不要。您几乎总是想要__init__
来代替。
>>> class A1:
... def __init__(self):
... raise ValueError()
...
>>> class B1(A1):
... def __init__(self):
... pass
...
>>> A1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
ValueError
>>> B1()
<__main__.B1 object at 0x7fa97b3f26d8>
请注意,现在如何获取实际的默认构造的B1
对象。
作为一般规则,如果要使用不可变类型(例如__new__
和str
)或构建新的元类,则只需要修改tuple
。您可以查看有关每种方法负责in the docs的详细信息。