في Python ، كيف يمكنني الاتصال بالفئة الفائقة عندما يكون اسمه لمرة واحدة اسمه؟
-
28-09-2019 - |
سؤال
لذلك ، لدي عدد كبير من فئات حمولة الرسائل لاتحاد واجهات برمجة التطبيقات التسلسلية ، كل منها لديه عدد من الحقول غير القابلة للتغيير ، وطريقة تحليل ، وبعض الطرق المشتركة. الطريقة التي أقوم بإنشائها هي أن كل منها سوف يرث من مسام لسلوكيات الميدان ، وتلقي الأساليب المشتركة من فئة الوالدين. ومع ذلك ، أواجه بعض الصعوبات مع البنائين:
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
من المكالمة ، لا يزال يبدو أنه يعمل ، ولكن لماذا؟ كيف يتم نقل هذه الحجج إلى المُنشئ إلى the namedtuple؟ هل هذا مضمون ، أو نتيجة عشوائية لكيفية MRO يتم تأسيسها؟
إذا أردت الابتعاد عن 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
, ، الخاص بك اسمه DifferentialSpeed_
, ، والفئة الأساسية المشتركة object
. لا يوجد أي من الأولين لديه __init__
الوظيفة على الإطلاق ، باستثناء تلك الموروثة من object
. namedtuple
لا يحتاج إلى __init__
, ، منذ تهيئة الطبقات غير القابلة للتغيير __new__
, الذي يسمى من قبل __init__
يجرى.
حيث super(DifferentialSpeed, self).__init__
يحل إلى التالي __init__
في سلسلة المكالمات ، التالي __init__
هو object.__init__
, ، مما يعني أنك تمرير حجج إلى هذه الوظيفة. لا يتوقع أي شيء-لا يوجد سبب لنقل الحجج إلى object.__init__
.
(اعتاد أن يقبل وتجاهل الحجج بصمت. هذا السلوك يختفي-لقد ذهب في بيثون 3-وهذا هو السبب في حصولك على إهمال.)
يمكنك تشغيل المشكلة بشكل أكثر وضوحًا عن طريق إضافة أ Payload.__init__
الوظيفة التي لا تأخذ حجج. عندما تحاول المرور على طول `*Kwargs, ، سوف يرفع خطأ.
الشيء الصحيح الذي يجب القيام به في هذه الحالة هو بالتأكيد إزالة **kwargs
الحجة ، واتصل فقط super(DifferentialSpeed, self).__init__()
. لا يأخذ أي حجج. DifferentialSpeed
هو يمر Payload
انها ملك الحجج ذلك Payload
, ويعمل بشكل أكبر في سلسلة المكالمات ، لا تعرف شيئًا عنها.
كما أشار الآخرون ، فإن tuples نوع غير قابل للتغيير ، والذي يجب تهيئته في __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)