سؤال

في هذا الكتاب بيثون باختصار (2nd Edition) هناك مثال يستخدم
فصول النمط القديم لإظهار كيف يتم حل الطرق في ترتيب الدقة الكلاسيكية و
كيف يتم تختلف مع الطلب الجديد.

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

class Base1(object):  
    def amethod(self): print "Base1"  

class Base2(Base1):  
    pass

class Base3(object):  
    def amethod(self): print "Base3"

class Derived(Base2,Base3):  
    pass

instance = Derived()  
instance.amethod()  
print Derived.__mro__  

الاتصال instance.amethod() مطبوعات Base1, ، ولكن حسب فهمي ل MRO بأسلوب جديد من الفصول يجب أن يكون الإخراج Base3. وبعد الاتصال Derived.__mro__ مطبوعات:

(<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)

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

هل كانت مفيدة؟

المحلول

الفرق الحاسم بين ترتيب القرار من أجل Legacy VS فئات النمط الجديد يأتي عند حدوث نفس فئة الأجداد أكثر من مرة واحدة في نهج "ساذج" وعمق الأول - على سبيل المثال، فكر في حالة "ميراث الماس":

>>> class A: x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'a'

هنا، النمط القديم، ترتيب القرار هو D - B - A - C - A: لذلك عند البحث عن DX، A هي القاعدة الأولى في ترتيب الحل لحلها، وبالتالي تخفي التعريف في C. في حين:

>>> class A(object): x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'c'
>>> 

هنا، نمط جديد، والنظام هو:

>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, 
    <class '__main__.A'>, <type 'object'>)

مع A اضطر إلى المجيء في قرار القرار مرة واحدة فقط وبعد كل فردينياته الفرعية، بحيث يتجاوز (IE، ج غير جيم x) في الواقع العمل بشكل معقول.

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

نصائح أخرى

ترتيب حل طريقة Python هو في الواقع أكثر تعقيدا من مجرد فهم نمط الماس. ل حقا فهم ذلك، نلقي نظرة على C3 الخطية. وبعد لقد وجدت أنه يساعد حقا في استخدام عبارات الطباعة عند تمديد الأساليب لتتبع الطلب. على سبيل المثال، ما رأيك في إخراج هذا النمط سيكون؟ (ملاحظة: من المفترض أن تكون "X" حوافين معبرين، وليس عقدة و ^ يدلون الأساليب التي تتصل بكثير ())

class G():
    def m(self):
        print("G")

class F(G):
    def m(self):
        print("F")
        super().m()

class E(G):
    def m(self):
        print("E")
        super().m()

class D(G):
    def m(self):
        print("D")
        super().m()

class C(E):
    def m(self):
        print("C")
        super().m()

class B(D, E, F):
    def m(self):
        print("B")
        super().m()

class A(B, C):
    def m(self):
        print("A")
        super().m()


#      A^
#     / \
#    B^  C^
#   /| X
# D^ E^ F^
#  \ | /
#    G

هل حصلت على Abdcefg؟

x = A()
x.m()

بعد الكثير من المحاكمة خطأ، توصلت إلى ترجمة رسمية رسمية رسمية لتفعيل C3 على النحو التالي: (شخص ما، اسمحوا لي أن أعرف ما إذا كان هذا خطأ.)

النظر في هذا المثال:

class I(G):
    def m(self):
        print("I")
        super().m()

class H():
    def m(self):
        print("H")

class G(H):
    def m(self):
        print("G")
        super().m()

class F(H):
    def m(self):
        print("F")
        super().m()

class E(H):
    def m(self):
        print("E")
        super().m()

class D(F):
    def m(self):
        print("D")
        super().m()

class C(E, F, G):
    def m(self):
        print("C")
        super().m()

class B():
    def m(self):
        print("B")
        super().m()

class A(B, C, D):
    def m(self):
        print("A")
        super().m()

# Algorithm:

# 1. Build an inheritance graph such that the children point at the parents (you'll have to imagine the arrows are there) and
#    keeping the correct left to right order. (I've marked methods that call super with ^)

#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^  I^
#        / | \  /   /
#       /  |  X    /   
#      /   |/  \  /     
#    E^    F^   G^
#     \    |    /
#       \  |  / 
#          H
# (In this example, A is a child of B, so imagine an edge going FROM A TO B)

# 2. Remove all classes that aren't eventually inherited by A

#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^
#        / | \  /  
#       /  |  X    
#      /   |/  \ 
#    E^    F^   G^
#     \    |    /
#       \  |  / 
#          H

# 3. For each level of the graph from bottom to top
#       For each node in the level from right to left
#           Remove all of the edges coming into the node except for the right-most one
#           Remove all of the edges going out of the node except for the left-most one

# Level {H}
#
#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^
#        / | \  /  
#       /  |  X    
#      /   |/  \ 
#    E^    F^   G^
#               |
#               |
#               H

# Level {G F E}
#
#         A^
#       / |  \
#     /   |    \
#   B^    C^   D^
#         | \ /  
#         |  X    
#         | | \
#         E^F^ G^
#              |
#              |
#              H

# Level {D C B}
#
#      A^
#     /| \
#    / |  \
#   B^ C^ D^
#      |  |  
#      |  |    
#      |  |  
#      E^ F^ G^
#            |
#            |
#            H

# Level {A}
#
#   A^
#   |
#   |
#   B^  C^  D^
#       |   |
#       |   |
#       |   |
#       E^  F^  G^
#               |
#               |
#               H

# The resolution order can now be determined by reading from top to bottom, left to right.  A B C E D F G H

x = A()
x.m()

النتيجة التي تحصل عليها صحيحة. حاول تغيير الفئة الأساسية من Base3 ل Base1 ومقارنة مع نفس التسلسل الهرمي للفصول الكلاسيكية:

class Base1(object):
    def amethod(self): print "Base1"

class Base2(Base1):
    pass

class Base3(Base1):
    def amethod(self): print "Base3"

class Derived(Base2,Base3):
    pass

instance = Derived()
instance.amethod()


class Base1:
    def amethod(self): print "Base1"

class Base2(Base1):
    pass

class Base3(Base1):
    def amethod(self): print "Base3"

class Derived(Base2,Base3):
    pass

instance = Derived()
instance.amethod()

الآن مخرجات:

Base3
Base1

اقرأ هذا التفسير للمزيد من المعلومات.

كنت ترى هذا السلوك لأن قرار الأسلوب هو العمق أولا، وليس العرض الأول. يبدو ميراث Dervied

         Base2 -> Base1
        /
Derived - Base3

وبالتالي instance.amethod()

  1. الشيكات Base2، لا يجد أميثود.
  2. يرى أن Base2 موروثة من Base1، والتحقق من Base1. Base1 لديه أ amethod, ، لذلك يطلق عليه.

وينعكس هذا في Derived.__mro__. وبعد مجرد تكرار Derived.__mro__ وتوقف عند العثور على الطريقة التي تبحث عنها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top