문제

책에서 간단히 말하는 파이썬 (2 판) 사용하는 예가 있습니다
방법이 고전적인 해상도 순서로 해결되는 방법을 보여주는 구식 수업과
새로운 질서와 어떻게 다른가?

예제를 새로운 스타일로 다시 작성하여 동일한 예제를 시도했지만 결과는 구식 수업에서 얻은 것과 다르지 않습니다. 예제를 실행하기 위해 사용하는 파이썬 버전은 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를 더 잘 이해하도록 도와주세요.

도움이 되었습니까?

해결책

레거시와 새로운 스타일 클래스에 대한 해상도 순서 사이의 중요한 차이점은 동일한 조상 클래스가 "순진한", 깊이 우선 접근 방식에서 두 번 이상 발생할 때 발생합니다.

>>> 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 모든 서브 클래스 후에 한 번만 해상도 순서로 강제로 오도록 강요 당했으므로 재정의 (예 : C의 멤버 재정의 x) 실제로 현명하게 작동합니다.

구식 클래스를 피해야하는 이유 중 하나입니다. "다이아몬드와 같은"패턴을 가진 다중 상속은 새로운 스타일과 관련하여 현명하게 작동하지 않습니다.

다른 팁

Python의 메소드 해상도 순서는 실제로 다이아몬드 패턴을 이해하는 것보다 더 복잡합니다. 에게 진짜 이해하고 살펴보십시오 C3 선형화. 순서를 추적하기 위해 메소드를 확장 할 때 인쇄문을 사용하는 것이 실제로 도움이된다는 것을 알았습니다. 예를 들어,이 패턴의 출력은 무엇이라고 생각하십니까? (참고 : 'x'는 노드가 아닌 두 개의 교차 가장자리라고 가정하고 ^ super ()를 호출하는 메소드를 나타냅니다).

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에는 a가 있습니다 amethod, 그래서 그것은 호출됩니다.

이것은 반영됩니다 Derived.__mro__. 단순히 반복하십시오 Derived.__mro__ 그리고 당신이 찾는 방법을 찾을 때 중지하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top