向内置类型的多重继承子类的构造函数中添加可选参数? [英] Adding optional parameters to the constructors of multiply-inheriting subclasses of built-in types?
问题描述
我的多重继承赋不强.我正在尝试创建一个超类,该超类的__init__
带有一个可选的命名参数及其子类,它们也都继承自内置类型.可悲的是,我似乎不知道如何进行这项工作:
My multiple-inheritance-fu is not strong. I am trying to create a superclass whose __init__
takes an optional named parameter and subclasses of it which also inherit from built-in types. Sadly, I appear to have no idea how to make this work:
>>> class Super(object):
name = None
def __init__(self, *args, name=None, **kwargs):
self.name = name
super().__init__(self, *args, **kwargs)
>>> class Sub(Super, int):
pass
>>> Sub(5)
5
>>> Sub(5, name="Foo")
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
Sub(5, name="Foo")
TypeError: 'name' is an invalid keyword argument for this function
(我也尝试了不使用super()
调用,但是结果是相同的.)
(I've also tried it without the super()
call, but the result was the same.)
也许对多重继承有更好了解的人可以为我指明正确的方向?
Perhaps someone with better knowledge of multiple inheritance can point me in the right direction?
更新:
It's still a little hacky (by changining __new__
's signature partway through construction), but it will work as long as the superclass appears in the subclasses' MROs before the built-in type and defining __new__
this way allows me to make subclasses which work with different built-in types without adding a separate __new__
to each one.
>>> class Super(object):
name = None
def __new__(cls, *args, name=None, **kwargs):
inner = super().__new__(cls, *args, **kwargs)
inner.name = name
return inner
>>> class Sub(Super, int):
pass
>>> Sub(5)
5
>>> Sub(5, name="Foo")
5
>>> _.name
'Foo'
推荐答案
您不能将任意参数(无论是位置参数还是命名参数)传递给同等任意的超类(即,当前的叶子类型是)-出于极好的原因,大多数类型和类也不接受任意参数-引用Zen of Python
,
You just cannot pass arbitrary parameters (whether positional or named ones) to an equally arbitrary superclass (i.e., "immediately previous type in the mro
of whatever the current leaf type is") -- most types and classes just don't accept arbitrary parameters, for excellent reasons too -- quoting from the middle of the Zen of Python
,
Errors should never pass silently.
Unless explicitly silenced.
,在大多数情况下,致电(例如)int(name='booga')
当然是错误的.
and in most cases, calling (e.g.) int(name='booga')
would of course be an error.
如果您要怪异地命名class Super
以便能够传递"任意参数,则还必须确保曾经用作基础的所有类都可以处理该参数-例如,int
可以使用一个参数(或恰好两个:字符串和基数)进行调用,因此,如果对您而言绝对重要的是class Sub
可以可以从传递buck的Super
和 int,则必须进行字段设置,例如:
If you want you weirdly-named class Super
to be able to "pass on" arbitrary parameters, you must also ensure that all classes ever used as bases after it can handle that -- so, for example, int
can be called with one parameter (or exactly two: a string and a base), so, if it's absolutely crucial to you that class Sub
can multiply inherit from the buck-passing Super
and int, you have to field that, e.g.:
class Int(int):
def __new__(cls, *a, **k):
return int.__new__(Int, a[0] if a else 0)
请注意,您必须覆盖__new__
,而不是 __init__
(如果您也覆盖后者,则无害,但仍然无关紧要):__new__
时间设置该值.
Note that you must override __new__
, not __init__
(it does no harm if you also override the latter, but it's irrelevant anyway): int
is immutable so the value has to be set at __new__
time.
现在,类似
>>> class X(Super, Int): pass
...
>>> X(23, za='zo')
23
>>>
工作.但是请注意,X
必须是Int
(我们对int
进行消毒的版本的int
)的子类,而不是int
本身的不是,而int
的确是宽容的
work. But note that X
must subclass from Int
(our __new__
-sanitizing version of int
), not from int
itself, which, quite properly, has an unforgiving __new__
!-)
这篇关于向内置类型的多重继承子类的构造函数中添加可选参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!