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

发布于 2024-09-30 03:35:54 字数 1556 浏览 13 评论 0原文

因此,我有大量用于串行 API 的消息有效负载类,每个类都有许多不可变字段、一个解析方法和一些共享方法。我构建此结构的方式是,每个都将从字段行为的命名元组继承,并从父类接收通用方法。但是,我在构造函数方面遇到了一些困难:

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)

这可以工作,但我收到以下警告:

DeprecationWarning: object.__init__() takes no parameters
  super(DifferentialSpeed, self).__init__(**kwargs)

如果我从调用中删除 **kwargs ,它似乎仍然可以工作,但为什么呢?构造函数的这些参数如何传递给namedtuple?这是有保证的,还是 mro 建立的随机结果?

如果我想远离 super,并以旧的方式进行操作,是否有某种方法可以访问namedtuple 来调用其构造函数?我宁愿不必这样做:

DifferentialSpeed_ = namedtuple('DifferentialSpeed_', 
    'left_speed right_speed left_accel right_accel')
class DifferentialSpeed(Payload, DifferentialSpeed_):

似乎有点冗长且不必要。

我在这里最好的行动方针是什么?

So, I have a large number of message Payload classes for a serial API, each of which has a number of immutable fields, a parse method, and some methods which are shared. The way I'm structuring this is that each will inherit from a namedtuple for the field behaviours, and receive the common methods from a parent class. However, I'm having some difficulties with the constructors:

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)

This works, but I get the following warning:

DeprecationWarning: object.__init__() takes no parameters
  super(DifferentialSpeed, self).__init__(**kwargs)

If I remove **kwargs from the call, it still seems to work, but why? How are those arguments to the constructor getting passed through to the namedtuple? Is this guaranteed, or a random result of how the mro gets established?

If I wanted to stay away from super, and do it the old way, is there some way I can access the namedtuple to call its constructor? I'd rather not have to do this:

DifferentialSpeed_ = namedtuple('DifferentialSpeed_', 
    'left_speed right_speed left_accel right_accel')
class DifferentialSpeed(Payload, DifferentialSpeed_):

Seems kind of verbose and unnecessary.

What's my best course of action here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅唱々樱花落 2024-10-07 03:35:54

对于初学者来说,namedtuple(whatever)继承自tuple,它是不可变的,并且不可变类型不会打扰__init__,因为到时候__init__ 被称为对象已经被构造。如果您想将参数传递给 namedtuple 基类,则必须重写 __new__

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

For starters, namedtuple(whatever) inherits from tuple, which is immutable, and immutable types don't bother with __init__, because by the time __init__ is called the object is already constructed. If you want to pass arguments to the namedtuple base class you'll have to override __new__ instead.

You can see the definition of the result of namedtuple() by passing in a verbose=true argument; I find it educational.

安静被遗忘 2024-10-07 03:35:54

您有三个基类:Payload、namedtuple DifferentialSpeed_ 和公共基类object。除了从 object 继承的函数之外,前两个都没有 __init__ 函数。 namedtuple 不需要 __init__,因为不可变类的初始化是由 __new__ 完成的,它在 __init__ 之前调用代码> 已运行。

由于 super(DifferentialSpeed, self).__init__ 解析为调用链中的下一个 __init__,因此下一个 __init__object.__init__,这意味着您正在向该函数传递参数。它不需要任何东西——没有理由将参数传递给object.__init__

(它过去接受并默默地忽略参数。这种行为已经消失了——它在 Python 3 中消失了——这就是为什么你会收到 DeprecationWarning。)

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

在这种情况下,正确的做法几乎肯定是删除 **kwargs 参数,然后调用 super(DifferentialSpeed, self).__init__()。它不需要任何论证; DifferentialSpeed 正在向 Payload 传递其自己的参数,而 Payload 以及调用链下游的函数对此一无所知。

You have three base classes: Payload, your namedtuple DifferentialSpeed_, and the common base class object. Neither of the first two have an __init__ function at all, except for the one inherited from object. namedtuple doesn't need an __init__, since the initialization of immutable classes is done by __new__, which is called before __init__ is run.

Since super(DifferentialSpeed, self).__init__ resolves to the next __init__ in the call chain, the next __init__ is object.__init__, which means you're passing arguments to that function. It doesn't expect any--there's no reason to be passing arguments to object.__init__.

(It used to accept and silently ignore arguments. That behavior is going away--it's gone in Python 3--which is why you get a DeprecationWarning.)

You can trigger the problem more clearly by adding a Payload.__init__ function that takes no arguments. When you try to pass along `*kwargs, it'll raise an error.

The correct thing to do in this case is almost certainly to remove the **kwargs argument, and just call super(DifferentialSpeed, self).__init__(). It doesn't take any arguments; DifferentialSpeed is passing Payload its own arguments that Payload, and functions further down the call chain, know nothing about.

缘字诀 2024-10-07 03:35:54

正如其他人指出的那样,元组是一种不可变类型,必须在其 __new__() 而不是其 __init__() 方法中初始化 - 因此您需要添加前者在你的子类中(并摆脱后者)。以下是如何将其应用于您的示例代码。唯一的其他更改是在开头添加 from import... 语句。

注意: cls 必须在 __new__() 中的 super() 调用中传递两次,因为它是静态的方法,尽管它是特殊情况,因此您不必将其声明为一种。

from collections import namedtuple

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

class DifferentialSpeed(Payload, namedtuple('DifferentialSpeed_',
    'left_speed right_speed left_accel right_accel')):
    #### NOTE: __new__ instead of an __init__ method ####
    def __new__(cls, **kwargs):
        self = super(DifferentialSpeed, cls).__new__(cls, **kwargs)
        # TODO: Field verification
        print("foo")
        return self

    @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)

As others have pointed-out, tuples are an immutable type, which must be initialized in their __new__() instead of their __init__() method -- so you need to add the former in your subclass (and get rid of the latter). Below is how this would be applied to your example code. The only other change was adding a from import... statement to the beginning.

Note: cls has to be passed twice in the super() call in __new__() because it's a static method although it is special-cased so you don't have to declare it to be one.

from collections import namedtuple

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

class DifferentialSpeed(Payload, namedtuple('DifferentialSpeed_',
    'left_speed right_speed left_accel right_accel')):
    #### NOTE: __new__ instead of an __init__ method ####
    def __new__(cls, **kwargs):
        self = super(DifferentialSpeed, cls).__new__(cls, **kwargs)
        # TODO: Field verification
        print("foo")
        return self

    @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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文