في Python ، كيف يمكنني الاتصال بالفئة الفائقة عندما يكون اسمه لمرة واحدة اسمه؟

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

سؤال

لذلك ، لدي عدد كبير من فئات حمولة الرسائل لاتحاد واجهات برمجة التطبيقات التسلسلية ، كل منها لديه عدد من الحقول غير القابلة للتغيير ، وطريقة تحليل ، وبعض الطرق المشتركة. الطريقة التي أقوم بإنشائها هي أن كل منها سوف يرث من مسام لسلوكيات الميدان ، وتلقي الأساليب المشتركة من فئة الوالدين. ومع ذلك ، أواجه بعض الصعوبات مع البنائين:

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)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top