2012-11-09 3 views
4

__init__ 실행 순서를 올바르게 설정하려고합니다. 계층 구조는 두 가지로 구성됩니다. 왼쪽 브랜치는 오른쪽 브랜치의 추상 메소드를 구현한다. 오른쪽 지점에는 또한 분할이 있습니다. 이제 저는 그들에게 실행을 원합니다 : 위에서 아래로, 그리고 위에서 아래로 오른쪽에서 왼쪽으로.Python에서 다중 상속을 사용하여 특정 __init__ 실행을 강제 실행합니다.

파이썬 3에서이를 달성 할 수있는 방법이 있습니까?

에게 는

그래서 기본적으로 (이하지 않는) 순서대로 번호를 인쇄해야 다음과 L2는 R2의 추상 메소드를 구현하기 때문에

from abc import abstractmethod, ABCMeta 

class L1: 
    def __init__(self): 
     super().__init__() 
     print(1) 

class R1(metaclass=ABCMeta): 
    def __init__(self): 
     super().__init__() 
     print(3) 

    @abstractmethod 
    def m(self): 
     pass 

class L2(L1): 
    def __init__(self): 
     super().__init__() 
     print(2) 

    def m(self): 
     pass 

class R2a(R1): 
    def __init__(self): 
     super().__init__() 
     print(4) 

class R2b(R1): 
    def __init__(self): 
     super().__init__() 
     print(4) 

class X(L2, R2a): 
    pass 

class Y(L2, R2b): 
    pass 

x = X() 
print("--") 
y = Y() 

불행하게도 내가 L2와 R2의 순서를 변경할 수 없습니다 (이있을 것 오류가 생길 경우).

가능합니까? 내가 중요하지 않습니다 생각했지만, 내가 거기, 내 진짜 구조에서 점에 유의하고자 :

편집 (? 당신은 쉬운 문제 같은 종류를 해결하기 위해 MRO에 대해 생각하는 좋은 방법을 알고 계십니까) 실제로는 L2a (L1), L2b (L1) 및 L2 (L1a, L2a)와 같이 L면의 다이아몬드입니다. 그것은 일부 기능을 완전히 분리하는 것입니다.

+0

"새 스타일 클래스"를 얻으려면'object' :'class L1 (object) :'의 최상위 클래스를 파생시켜야합니다. – Ber

+0

@Ber, 아니요, 그는 Python 3을 사용하고 있습니다 (그렇지 않으면 메타 클래스 구문이 작동하지 않습니다). 그래서 그는 객체에서 명시 적으로 상속 할 필요가 없습니다. – Duncan

답변

1

나는 슈퍼의 사용을 방지하기 위해 선호 :

class A: 
    def __init__(self): 
     print('init A') 

class B: 
    def __init__(self): 
     print('init B') 

class C(B,A): 
    def __init__(self): 
     A.__init__(self) 
     B.__init__(self) 
     print('init C') 

c = C() 

이 인쇄 :

init A 
init B 
init C 

그래서 특정 상황에 단지 _ 전화 당신이 원하는 순서 유념하라 init을합니다. 정말. 그냥 시도 해 봐. 다이아몬드 또는 아무 다이아몬드 그것은 잘 작동합니다.

EG :

class X(L2,R2a): 
    def __init__(self): 
     L1.__init__(self) 
     L2.__init__(self) 
     R1.__init__(self) 
     R2a.__init__(self) 

계층 구조에서 더 높은 물건 초기화를 호출해야하고 다음 그냥 부울 플래그을 특정 개체에 대해 반복적으로 특정 클래스의 초기화하기 함수를 호출 두려워하는 경우 . 예를 들어

:

class L1: 
    def __init__(self): 
     try: 
      if self.l1_initialised: 
       return 
     except NameError: 
      self.l1_initialised = True 
     blah blah blah 
+1

그러나 문제는 수퍼 클래스가 두 번 호출되는 다이아몬드 구조입니다. 나는 실제로 나의 L2 클래스도 쪼개어지고있다라고 언급하지 않았다. – Gerenuk

+2

@Sheena : 메소드 (MRO) 알고리즘을 작동시키기 위해 super()를 사용해야합니다. http://www.python.org/download/releases/2.3/mro/ – Ber

+0

@Ber : 감사합니다. 그것을 들여다 보았다. 나는 전에 이런 일을하는 방식에 결코 문제가 없었다. – Sheena

3

방법에 대해 :

from abc import abstractmethod, ABCMeta 

class L1: 
    def __init__(self): 
     self.init() 
     super().__init__() 
    def init(self): 
     print(1) 

class R1(metaclass=ABCMeta): 
    def __init__(self): 
     print(3) 
     super().__init__() 

    @abstractmethod 
    def m(self): 
     pass 

class L2(L1): 
    def __init__(self): 
     super().__init__() 
    def init(self): 
     super().init() 
     print(2) 

    def m(self): 
     pass 

class R2a(R1): 
    def __init__(self): 
     super().__init__() 
     print(4) 


class R2b(R1): 
    def __init__(self): 
     super().__init__() 
     print(4) 

class X(L2, R2a): 
    pass 

class Y(L2, R2b): 
    pass 

x = X() 
print([cls.__name__ for cls in X.mro()]) 

1 
2 
3 
4 
['X', 'L2', 'L1', 'R2a', 'R1', 'object'] 

를 산출하는 난 당신이 MRO, ['X', 'L2', 'L1', 'R2a', 'R1', 'object'] 변경할 수 있다고 생각하지 않습니다. 그러나 super().__init__() 이전 또는 이후에 초기화 문을 배치하도록 선택할 수 있습니다.

super().__init__() 앞에 인쇄 문을두면 MRO 순으로 인쇄 문이 표시됩니다. 나중에 배치하면 순서가 바뀝니다.

주문을 부분적으로 취소하려는 경우 : L2 이전의 L1, R2a 이전의 R1.

self.init()을 호출하여 L1에 도달하면 MRO 체인의 처음부터 다시 시작하고 init을 원하는 순서대로 호출합니다 (L1, L2).