在Python中,当超类是一次性命名元组时,如何调用它?
因此,我有大量用于串行 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于初学者来说,
namedtuple(whatever)
继承自tuple
,它是不可变的,并且不可变类型不会打扰__init__
,因为到时候__init__
被称为对象已经被构造。如果您想将参数传递给namedtuple
基类,则必须重写__new__
。通过传入
verbose=true
参数可以看到namedtuple()
结果的定义;我觉得它很有教育意义。For starters,
namedtuple(whatever)
inherits fromtuple
, 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 thenamedtuple
base class you'll have to override__new__
instead.You can see the definition of the result of
namedtuple()
by passing in averbose=true
argument; I find it educational.您有三个基类:
Payload
、namedtupleDifferentialSpeed_
和公共基类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 namedtupleDifferentialSpeed_
, and the common base classobject
. Neither of the first two have an__init__
function at all, except for the one inherited fromobject
.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__
isobject.__init__
, which means you're passing arguments to that function. It doesn't expect any--there's no reason to be passing arguments toobject.__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 callsuper(DifferentialSpeed, self).__init__()
. It doesn't take any arguments;DifferentialSpeed
is passingPayload
its own arguments thatPayload
, and functions further down the call chain, know nothing about.正如其他人指出的那样,元组是一种不可变类型,必须在其
__new__()
而不是其__init__()
方法中初始化 - 因此您需要添加前者在你的子类中(并摆脱后者)。以下是如何将其应用于您的示例代码。唯一的其他更改是在开头添加from import...
语句。注意:
cls
必须在__new__()
中的super()
调用中传递两次,因为它是静态的方法,尽管它是特殊情况,因此您不必将其声明为一种。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 afrom import...
statement to the beginning.Note:
cls
has to be passed twice in thesuper()
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.