在Python中,当它是一个一次性的命名元组时,如何调用超类?

mik*_*vis 13 inheritance multiple-inheritance super namedtuple python-3.x

因此,我有一个用于串行API的大量消息Payload类,每个类都有许多不可变字段,一个解析方法和一些共享的方法.我构造它的方式是每个都将从字段行为的namedtuple继承,并从父类接收公共方法.但是,我在构造函数方面遇到了一些困难:

class Payload:
    def test(self):
        print("bar")

class DifferentialSpeed(Payload, namedtuple('DifferentialSpeed_', 
    'left_speed right_speed left_accel right_accel')):
    __slots__ = ()
    def __init__(self, **kwargs):
        super(DifferentialSpeed, self).__init__(**kwargs)
        # TODO: Field verification
        print("foo")

    @classmethod
    def parse(self, raw):
        # Dummy for now
        return self(left_speed = 0.0, right_speed = 0.1,
                    left_accel = 0.2, right_accel = 0.3)

    def __str__(self):
        return "Left Speed: %fm/s\nRight Speed: %fm/s\n"\
            "Left Acceleration: %fm/s^2\nRight Acceleration: %fm/s^2" % (
            self.left_speed, self.right_speed, self.left_accel, self.right_accel)


payload = DifferentialSpeed.parse('dummy')
print(payload)
Run Code Online (Sandbox Code Playgroud)

这有效,但我得到以下警告:

DeprecationWarning: object.__init__() takes no parameters
  super(DifferentialSpeed, self).__init__(**kwargs)
Run Code Online (Sandbox Code Playgroud)

如果我**kwargs从通话中删除,它似乎仍然有效,但为什么?如何将构造函数的参数传递给namedtuple?这是保证,还是mro如何建立的随机结果?

如果我想远离超级,并以旧的方式做,有什么方法可以访问namedtuple来调用它的构造函数?我宁愿不必这样做:

DifferentialSpeed_ = namedtuple('DifferentialSpeed_', 
    'left_speed right_speed left_accel right_accel')
class DifferentialSpeed(Payload, DifferentialSpeed_):
Run Code Online (Sandbox Code Playgroud)

似乎有点冗长和不必要.

我最好的行动方式是什么?

Pet*_*ley 27

对于初学者来说,namedtuple(whatever)继承自的tuple,不可变的,不可变的类型都不会打扰__init__,因为在__init__被调用的时候已经构造了对象.如果要将参数传递给namedtuple基类,则必须覆盖它__new__.

你可以namedtuple()通过传入一个verbose=true参数来看到结果的定义; 我觉得它有教育意义.


Gle*_*ard 5

您有三个基类:Payload您的namedtuple DifferentialSpeed_和公共基类object.前两个都没有任何__init__功能,除了继承自的功能object. namedtuple不需要__init__,因为不可变类的初始化是由完成的__new__,在__init__运行之前调用.

由于super(DifferentialSpeed, self).__init__解析到__init__调用链中的下一个,下一个__init__object.__init__,这意味着你将参数传递给该函数.它不期望任何 - 没有理由传递参数object.__init__.

(它曾经接受并默默地忽略了参数.这种行为正在消失 - 它已经在Python 3中消失了 - 这就是为什么你得到了一个弃用警告.)

您可以通过添加Payload.__init__不带参数的函数来更清楚地触发问题.当你试图传递`*kwargs时,它会引发一个错误.

在这种情况下,正确的做法是删除**kwargs参数,然后调用super(DifferentialSpeed, self).__init__().它没有任何论据; DifferentialSpeed正在传递Payload自己的论点Payload,并且在调用链中进一步发挥作用,对此一无所知.