向内置类型的多重继承子类的构造函数中添加可选参数? [英] Adding optional parameters to the constructors of multiply-inheriting subclasses of built-in types?

查看:80
本文介绍了向内置类型的多重继承子类的构造函数中添加可选参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的多重继承赋不强.我正在尝试创建一个超类,该超类的__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?

更新:

这是我最终基于它还是有点棘手(通过在构造过程中更改__new__的签名),但是只要超类出现在子类的MRO中,只要内置类之前的超类出现并以这种方式定义__new__,它就可以工作允许我创建适用于不同内置类型的子类,而无需为每个子类添加单独的__new__.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆