“ mro ()” ทำอะไร?


คำตอบ:


212

ตามไปดู ... :

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

ตราบใดที่เรามีการสืบทอดเพียงครั้งเดียว__mro__ก็เป็นเพียงทูเพิลของคลาสฐานของมันฐานของฐานและอื่น ๆ จนถึงobject(ใช้ได้กับคลาสสไตล์ใหม่เท่านั้น)

ตอนนี้มีหลายมรดก ... :

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

... คุณยังได้รับความมั่นใจว่า__mro__ไม่มีคลาสใดซ้ำกันและไม่มีคลาสใดมาตามบรรพบุรุษบันทึกคลาสที่เข้าครั้งแรกในระดับเดียวกันของการสืบทอดหลายรายการ (เช่น B และ C ในตัวอย่างนี้) อยู่ใน__mro__จากซ้ายไปขวา

ทุกแอตทริบิวต์ที่คุณได้รับในอินสแตนซ์ของคลาสไม่ใช่แค่เมธอดเท่านั้นที่มองขึ้นไปตามแนวคิด__mro__ดังนั้นหากมีมากกว่าหนึ่งคลาสในหมู่บรรพบุรุษกำหนดชื่อนั้นสิ่งนี้จะบอกคุณว่าจะพบแอตทริบิวต์ที่ใด - ในคลาสแรกใน__mro__ที่กำหนดชื่อ


9
สวัสดีอเล็กซ์มีความแตกต่างระหว่าง D .__ mro__ และ D.mro () หรือไม่
zjm1126

26
mroสามารถกำหนดได้โดย metaclass ที่เรียกว่าครั้งหนึ่งที่เริ่มต้นเรียนและผลที่ได้จะถูกเก็บไว้ใน__mro__- ดูdocs.python.org/library/...
Alex Martelli

23
เหตุใดจึงเรียกว่าmethod resolution orderแทนattribute resolution order ?
Bentley4

1
เช่นเดียว @ Alex เทลกล่าวและเนื้อหาของ python-history.blogspot.com/2010/06/...ที่MROแอตทริบิวต์ควรจะเพิ่มเมื่อคลาสใหม่ถูกนำมาใช้เป็นเพียงเมื่องูหลาม 2.2 MRO และ Python 2.3 MRO (C3) ใช้
andy

82

mro()ย่อมาจาก Method Resolution Order ส่งคืนรายการประเภทที่คลาสได้มาตามลำดับที่ค้นหาเมธอด

mro ()หรือ__mro__ ใช้งานได้กับคลาสรูปแบบใหม่เท่านั้น ใน python 3 ทำงานได้โดยไม่มีปัญหาใด ๆ แต่ใน python 2 คลาสเหล่านั้นจำเป็นต้องสืบทอดจากobject.


10

นี่อาจจะแสดงลำดับความละเอียด

class A(object):
    def dothis(self):
        print('I am from A class')

class B(A):
    pass

class C(object):
    def dothis(self):
        print('I am from C class')

class D(B, C):
    pass

d_instance= D()
d_instance.dothis()
print(D.mro())

และการตอบสนองจะเป็น

I am from A class
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>]

กฎคือความลึกก่อนซึ่งในกรณีนี้จะหมายถึง D, B, A, C

โดยปกติ Python จะใช้ลำดับความลึกเป็นอันดับแรกเมื่อค้นหาคลาสที่สืบทอดมา แต่เมื่อสองคลาสสืบทอดมาจากคลาสเดียวกัน Python จะลบการกล่าวถึงครั้งแรกของคลาสนั้นออกจาก mro


1
ดังที่คุณเห็นคำสั่งคือ D, B, A, C
Stryker

1
คุณหมายถึงอะไรโดย "Python ลบการกล่าวถึงครั้งแรกของคลาสนั้นออกจาก mro"?
Ruthvik Vaila

2
@RuthvikVaila: ฉันคิดว่าส่วนนั้นระบุไว้ไม่ดี ในบล็อกโพสต์เกี่ยวกับประวัติของ Python นี้ Guido van Rossum ได้กล่าวถึง (เกี่ยวกับโครงร่าง MRO ที่แนะนำใน Python 2.2) "ถ้าคลาสใดซ้ำกันในการค้นหานี้ทั้งหมดยกเว้นคลาสสุดท้ายเหตุการณ์จะถูกลบออกจากรายการ MRO" (เน้นของฉัน ) ซึ่งหมายความว่าสามารถลบ "การกล่าวถึง" ครั้งแรกของชั้นเรียนได้มากกว่า
martineau

1

ลำดับความละเอียดจะแตกต่างกันในการสืบทอดเพชร

class A(object):
    def dothis(self):
        print('I am from A class')


class B1(A):
    def dothis(self):
        print('I am from B1 class')
    # pass


class B2(object):
    def dothis(self):
        print('I am from B2 class')
    # pass


class B3(A):
    def dothis(self):
        print('I am from B3 class')


# Diamond inheritance
class D1(B1, B3):
    pass


class D2(B1, B2):
    pass


d1_instance = D1()
d1_instance.dothis()
# I am from B1 class
print(D1.__mro__)
# (<class '__main__.D1'>, <class '__main__.B1'>, <class '__main__.B3'>, <class '__main__.A'>, <class 'object'>)


d2_instance = D2()
d2_instance.dothis()
# I am from B1 class
print(D2.__mro__)
# (<class '__main__.D2'>, <class '__main__.B1'>, <class '__main__.A'>, <class '__main__.B2'>, <class 'object'>)

แต่ทำไมความละเอียดถึงแตกต่างกัน?
Vadim

ในสถานการณ์จำลองการสืบทอดหลายแอ็ตทริบิวต์ที่ระบุจะถูกค้นหาก่อนในคลาสปัจจุบัน หากไม่พบการค้นหาจะดำเนินต่อไปในคลาสพาเรนต์แบบเจาะลึกก่อนซ้ายขวาโดยไม่ต้องค้นหาคลาสเดียวกันซ้ำ
Girish Gupta

ขอโทษ แต่ฉันไม่เข้าใจว่าทำไมในกรณีแรกมันถึงไปclass B3แต่ในกรณีที่สองมันเป็นclass Aหลังจากนั้นclass B1
Vadim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.