2017-09-23 18 views
3

(파이썬 3.6, mypy 0.521)을위한 완벽한 서명을 찾고 코드와 함께 작동하고, int, float, complex뿐만 아니라 datetime.timedelta에 대한 올바른 결과를 생성합니다. 서명을 추가 할 때 문제가 나타납니다. 나는 다음을 시도했다 :Mypy :</p> <pre><code>def avg(xs): it = iter(xs) try: s = next(it) i = 1 except StopIteration: raise ValueError("Cannot average empty sequence") for x in it: s += x i += 1 return s/i </code></pre> <p>이의 좋은 점 : 나는 다음과 같은 기능을위한 완벽한 기능의 서명을 마련하기 위해 노력하고있어 평균 기능

def avg(xs: t.Iterable[t.Any]) -> t.Any: ... 

그러나 이제 호출자는 결과를 캐스팅해야한다.

def avg(xs: t.Iterable[T]) -> T: ... 

T은 더하기 또는 나눗셈을 지원하지 않으므로 실패합니다. int/intfloat 때문에

N = TypeVar("N", int, float, complex, datetime.timedelta) 
def avg(xs: t.Iterable[N]) -> N: ... 

실패; //을 사용하면 거의 모든 경우에 대해 잘못된 결과가 나타납니다. 덧셈과 나눗셈이 지원되는 한 다른 유형에 대해서도 코드가 작동해야하기 때문에 짜증납니다.

N = TypeVar("N", float, complex, datetime.timedelta) 
def avg(xs: t.Iterable[N]) -> N: ... 

이것은 거의 완벽하지만, 나중에 쿼터니언을 던지기로 결정하면 mypy가 불평 할 것입니다.

... 그 다음 나는 또한 abctyping.overload와 함께 무엇인가 노력하고 있었다. 그러나 그것은 나를 아무 곳에도 붙 잡지 않았다.

mypy --strict에서 가장 멋진 해결책은 무엇입니까?

+0

그것은 플로트/INT 비대칭 당신이 정말이에 대한 일관된 서명을 생성 할 수 없음을 의미처럼 보인다. int와 float에 대해 숫자로 의미있는 결과를 생성하지만'avg ([list of ints])'는 float을 생성하고 avg ([list of floats])는 또한 float을 생성합니다. 이것은 함수가 주어진 형과 때로는 다른 형을 반환하기 때문에 입력 형식에 따라 일관되게 정의 할 수있는 반환 형식이 없다는 것을 의미합니다. mypy는 "numbers"와 같은 유형을 허용합니까 (numbers.Number'에서와 같이)? – BrenBarn

+0

Crazily,'numbers.Number'는'__add__' 또는 다른 표준 산술 연산을 정의하지 않으므로'지원되지 않는 왼쪽 피연산자 유형 + ("Number")','/ ("Number" – rollcat

답변

1

그래서 불행히도 Python/PEP 484의 숫자 체계는 현재 다소 엉망입니다.

기술적으로는 "numeric tower"이며 파이썬에서 모든 "숫자와 유사한"엔티티가 준수해야하는 ABC 집합을 나타 내기로되어 있습니다.

또한, 많은 내장 유형 파이썬 (예 : intfloatcomplex, 그리고 timedelta) typeshed에서 이러한 상식에서 상속하지 않습니다는 -이 그 상식이 경우를 제외하고 (기본적으로 사용할 수 있음을 의미 이러한 ABC에서 명시 적으로 상속받은 사용자 정의 유형을 정의합니다.

그리고이 문제를 복합화하기 위해 typeshed의 numbers module is largely dynamically typed - 1 년 전쯤에 숫자 모듈을 수정하는 데 스윙을 걸었고, 당시의 mypy는 정확하게 입력 할 수 없을 정도로 강력했습니다. 숫자 타워.

mypy가 최근에 프로토콜 (예 : 구조적 입력)에 대한 실험적 지원을 구현했기 때문에 그 상황은 다소 고칠 수 있습니다. 이것은 정확히 우리가 문제를 해결하고 궁극적으로 숫자 타워를 수정하는 것입니다 (일단 프로토콜이 PEP 484와 타이핑 모듈에 추가되면).당신이해야 할 일을 지금은

은 다음과 같습니다

우리가 할 수있는 (python3 -m pip install -U git+git://github.com/python/mypy.git를 실행) Github에서에서 mypy의 최신 버전을 설치 typing_extensions 모듈 (python3 -m pip install typing_extensions)

  • 설치 다음과 같이 "추가 또는 나누기 지원"유형에 대한 프로토콜을 정의하십시오.

    from datetime import timedelta 
    
    from typing import TypeVar, Iterable 
    from typing_extensions import Protocol 
    
    T = TypeVar('T') 
    S = TypeVar('S', covariant=True) 
    
    class SupportsAddAndDivide(Protocol[S]): 
        def __add__(self: T, other: T) -> T: ... 
    
        def __truediv__(self, other: int) -> S: ... 
    
    def avg(xs: Iterable[SupportsAddAndDivide[S]]) -> S: 
        it = iter(xs) 
        try: 
         s = next(it) 
         i = 1 
        except StopIteration: 
         raise ValueError("Cannot average empty sequence") 
        for x in it: 
         s += x 
         i += 1 
        return s/i 
    
    reveal_type(avg([1, 2, 3])) 
    reveal_type(avg([3.24, 4.22, 5.33])) 
    reveal_type(avg([3 + 2j, 3j])) 
    reveal_type(avg([timedelta(1), timedelta(2), timedelta(3)])) 
    
    이 사용 mypy 실행는

    원하는대로, 다음과 같은 출력을 생성합니다

    test.py:27: error: Revealed type is 'builtins.float*' 
    test.py:28: error: Revealed type is 'builtins.float*' 
    test.py:29: error: Revealed type is 'builtins.complex*' 
    test.py:30: error: Revealed type is 'datetime.timedelta*' 
    
  • +0

    mypy'4fc4ae24'와 함께 작동하지만'6c409b4e'는 깨진 변화를 도입 한 것 같습니다 (더 이상'__builtins__'를 찾을 수 없습니다). 감사! – rollcat

    +0

    @rollcat - 임시 버그처럼 들리므로 현재 또는 내일 언젠가는 수정 될 것입니다. – Michael0x2a

    +0

    @ Michael0x2a, 구현 노력에 감사드립니다. 이것은 대단한 답변입니다! –