2017-03-03 4 views
1

mypy 문서에 따르면 클래스가 자신을 참조해야하는 경우 forward-reference을 사용할 수 있습니다.mypy에서 NamedTuple을 상속 한 클래스의 메소드에 대해 유형 확인을 구현하는 방법은 무엇입니까?

정상적인 클래스에서는 정상적으로 작동하지만 NamedTuple에서 상속 한 클래스를 사용하는 데 문제가 있습니다.

""" 
All this code runs without error on Python 3.6 

The question is why the 'B' class' __add__ method 
raises an error through mypy. 
""" 


from typing import * 

class A: 
    def __init__(self, x: int) -> None: 
     self.x = x 

    def __add__(self, other: 'A') -> 'A': 
     return type(self)(self.x + other.x) 

    def __str__(self) -> str: 
     return f'A(x={self.x})' 

A1 = A(1) 
A2 = A(2) 
A3 = A1 + A2 
print(A3) 

class B(NamedTuple('B', [('x', int)])): 

    # The following line will raise an error in mypy 
    # error: Argument 1 of "__add__" incompatible with supertype "tuple" 
    def __add__(self, other: 'B') -> 'B': 
     return type(self)(self.x + other.x) 

B1 = B(1) 
B2 = B(2) 
B3 = B1 + B2 
print(B3) 

업데이트 : Guido van Rossum 그 자신이 이후로 this question on Github에 응답했습니다.

나는 당신이 달성하고자하는 것을 100 % 확신하지는 않지만, 초기 예제를 토대로 클래스 B에 대해 +를 다시 정의하여 인스턴스에 요소 추가를 구현하려는 것으로 추측합니다. B. mypy가 기본적으로 지원하지 않는 이유는 "Liskov 대체 원칙"(Google에서 설명 할 수 있음)이라고하는 것입니다.

그러나 해결 방법이 있습니다. put # type : 오류가 발생한 행을 무시합니다 (def 행 추가). 이것은 소리가 나지 않지만 B 인스턴스를 튜플이라고 가정하고 튜플 연결을 시도하는 코드에 B 인스턴스를 전달하지 않는 한 원하는 것을 수행합니다.

+0

이상합니다. 클래스 B는 이미'__name__' 'B'가있는 클래스로부터 상속 받고 있습니다. 아마도 어쩌면 엉망입니다. 그래서'__mro__'은'(, __main __. B '>, , )와 같은 형태가됩니다. –

+0

'B'의 이름, 또는'namedtuple'에 넘겨주는 이름. 따라서 클래스 B (NamedTuple ('SuperB', [('x', int)]))) : ' –

+0

과 관련있을 수 있습니다. https://github.com/python/mypy/issues/1237 –

답변

1

B.__add__의 유형 선언은 B의 다른 인스턴스에 B의 인스턴스를 추가하는 경우에만 유효하다고 제안 (그리고 other.x 작동 할 것으로 예상하기 때문에 구현은, 그 백업). 그러나이 메서드는 tuple (namedtuple 통해)에서 오는 더 일반적인 __add__ 메서드를 재정의합니다. 두 튜플을 함께 연결할 수 있습니다. 따라서 오른쪽은 tuple 또는 tuple -subclass의 인스턴스 일 수 있습니다. 새 메소드의 인수 유형이 엄격하기 때문에 클래스는 (mypy의 관점에서) tuple의 적절한 하위 클래스가 아닙니다. 클래스의 인스턴스를 이전에 튜플이 사용 된 장소에 놓을 수 없으며 같은 방식으로 작동하게 할 수 없습니다.

이 기능을 고려해

def tuple_append(tup: tuple, value: any) -> tuple: 
    return tup1 + (value,) 

이 정상 튜플 작동하지만 tupB 인스턴스 중 하나를 통과하면, 그것은 당신이 tuple 서브 클래스의 인스턴스를 전달 되더라도 (실패합니다 함수의 타입 선언이 요구하는대로). 따라서 mypyB 유형을 유효하지 않은 것으로 간주합니다. B을 수락하면 올바른 형식 선언을 가진 다른 코드가 예기치 않게 중단 될 수 있습니다.

불행히도이 문제를 해결할 좋은 방법이 없다고 생각합니다. 파이썬에는 다른 언어에서하는 "개인 상속"이라는 개념이 없습니다. 공개적으로 하위 클래스가되지 않고 다른 클래스에서 구현을 상속하는 방법은 없습니다.