В Python, как мне позвонить супер классом, когда это разовая namedtuple?

StackOverflow https://stackoverflow.com/questions/4071765

Вопрос

Таким образом, у меня есть большое количество классов полезных нагрузок для передачи сообщений для последовательного 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? Это гарантировано или случайный результат того, как мро Установлено?

Если бы я хотел держаться подальше от Super, и сделайте это старым способом, есть ли, я могу получить доступ к именам, чтобы позвонить своему конструктору? Я бы предпочел не нужно сделать это:

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

Кажется видом излыбов и ненужным.

Какой мой лучший курс действий здесь?

Это было полезно?

Решение

Для начинающих, namedtuple(whatever) наследует от tuple, который неизбежен, и неизменные типы не беспокоятся __init__, потому что к тому времени __init__ называется объект уже построен. Если вы хотите пройти аргументы namedtuple Базовый класс, который вам придется переопределить __new__ вместо.

Вы можете увидеть определение результата namedtuple() проходя в verbose=true аргумент; Я нахожу это образовательным.

Другие советы

У вас есть три базовых классов: 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, и функционирует дальше по цепочке вызовов, ничего не знаешь.

Как указали другие, кортежи являются неизменным типом, который должен быть инициализирован в их __new__() вместо их __init__() Метод - поэтому вам нужно добавить первое в своем подклассе (и избавиться от последнего). Ниже приведено, как это будет применено к вашему примеру кода. Единственное другое изменение добавляло from import... утверждение к началу.

Примечание: cls должен быть передан дважды в super() вызывать __new__() Потому что это статический метод, хотя он особенный, поэтому вам не нужно объявлять его, чтобы быть одним.

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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top