AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79322581
Accepted
平田智剛
平田智剛
Asked: 2025-01-02 09:09:31 +0800 CST2025-01-02 09:09:31 +0800 CST 2025-01-02 09:09:31 +0800 CST

Este é um erro de falso positivo [substituição]? "Assinatura de (método) incompatível com supertipo"

  • 772

Embora a assinatura do método em Subseja compatível com Super, mypy rejeita a substituição: Signature of "method" incompatible with supertype "Super".

estou usando

  • python 3.13.1
  • meupy 1.14.0

Primeiro, fiz o seguinte test.pyi.

from typing import overload

class Super:
    def method(self, arg:Other|Super)->Super: pass

class Sub(Super):
    @overload
    def method(self, arg:Other|Sub)->Sub: pass
    @overload
    def method(self, arg:Super)->Super: pass

class Other: pass

Então, quando executei mypy test.pyina linha de comando, o mypy produziu o seguinte diagnóstico:

test.pyi:7: error: Signature of "method" incompatible with supertype "Super"  [override]
test.pyi:7: note:      Superclass:
test.pyi:7: note:          def method(self, arg: Other | Super) -> Super
test.pyi:7: note:      Subclass:
test.pyi:7: note:          @overload
test.pyi:7: note:          def method(self, arg: Other | Sub) -> Sub
test.pyi:7: note:          @overload
test.pyi:7: note:          def method(self, arg: Super) -> Super
Found 1 error in 1 file (checked 1 source file)

Verifiquei o tipo de E/S de ambos Super.methode Sub.methode descobri que não há nenhum padrão que viole o LSP (Princípio de Substituição de Liskov).

Sub.methodLata sobrecarregada

  • entrada argdo tipo Other|Super(= Other|Sub+ Super) e
  • tipo de saída Super(= Sub+ Super).

O tipo de entrada e saída acima corresponde à assinatura de Super.method.

Então, não tenho ideia do que ser Signature of "method" incompatible with supertype "Super".

A seguir está a tabela de E/S de method.

Eu\O Super.method Sub.method Comparado a Super, Subo retorno de é: Aderindo ao LSP*
Other Super Sub mais estreito Sim
Sub Super Sub mais estreito Sim
Super Super Super o mesmo Sim
Other|Sub Super Sub mais estreito Sim
Other|Super Super Super** o mesmo Sim

*O LSP exige que o tipo de retorno de um submétodo seja mais estreito ou igual ao tipo de retorno do supermétodo.

** Sub.methodretorna

  • Subquando Othera entrada e
  • Superquando Supera entrada,

então ele retorna Sub|Superquando Other|Supera entrada.
Sub|Supersignifica Super.

Como você pode ver na tabela acima, não há padrões que violem o LSP.


Então, acho que a mensagem de erro mypy Signature of "method" incompatible with supertype "Super"está incorreta.

Meu código está errado?

Além disso, se meu código não estiver errado e a mensagem de erro do mypy estiver errada, onde posso perguntar?


PS Uma maneira rápida de esconder o erro.

Embora não seja uma solução completa, encontrei uma maneira simples de esconder o erro.

from typing import overload

class Super:
    def method(self, arg:Other|Super)->Super: pass

class Sub(Super):
    @overload
    def method(self, arg:Other|Sub)->Sub: pass
    @overload
    def method(self, arg:Super)->Super: pass
    # Start of hiding error
    @overload
    def method( # type: ignore[overload-cannot-match]
               self, arg:Other|Super)->Super: pass
    # End of hiding error

class Other: pass

Como uma última sobrecarga, adicionei um Sub.methodcom a mesma assinatura exata de Super.method. No entanto, quando esse problema for resolvido em uma versão futura, isso significará que o código que adicionei não será alcançado e devemos obter um [overload-cannot-match]erro. Portanto, adicionei # type: ignore[overload-cannot-match]para ignorar esse erro com antecedência.

(À primeira vista, pode parecer que estou simplesmente silenciando erros com type: ignore, mas isso não é relevante para o mypy no momento. Isso é apenas um impedimento contra erros futuros.)

python
  • 1 1 respostas
  • 97 Views

1 respostas

  • Voted
  1. Best Answer
    STerliakov
    2025-01-03T01:20:47+08:002025-01-03T01:20:47+08:00

    Conforme apontado em um tíquete de direitos autorais sobre isso , a especificação de digitação menciona esse comportamento explicitamente:

    Se um callable Bfor sobrecarregado com duas ou mais assinaturas, ele será atribuível a callable Ase pelo menos uma das assinaturas sobrecarregadas Bfor atribuível aA

    Há um ticket mypy perguntando sobre o mesmo problema.

    No entanto, seu código é de fato seguro, e a tabela em seu post prova isso. Isso é apenas uma limitação da especificação e/ou dos typecheckers.

    Conforme discutido nos comentários, pode parecer que o problema é o próprio tipo de união ( Other | Supernão pode ser despachado para nenhuma das sobrecargas), mas não é verdade: mypy usa matemática de união nesse caso, e o tipo de retorno de chamada sobrecarregado é uma união de tipos de retorno de sobrecargas correspondentes se todos os membros da união puderem ser despachados para um deles. Aqui está a fonte onde essa mágica acontece, leia os comentários lá se estiver interessado - o caminho do verificador principal está bem documentado.

    Agora, dado que seu código não passa pela verificação de tipo apenas devido a um problema de verificação de tipo/especificação, você tem várias opções:

    • # type: ignore[override]- por que não? Seu override está seguro, apenas diga ao mypy para calar a boca.

    • Adicione uma assinatura para corresponder aos requisitos de especificação como no seu último parágrafo. Mas, por favor, não adicione um comentário ignore não utilizado - há um --warn-unused-ignoressinalizador para mypyo qual é realmente útil. Não adicione tal ignore, apenas adicione um comentário de texto livre explicando o problema e vinculando aqui ou ao problema mypy.

    • Apenas estenda a segunda assinatura. Isso é seguro - sobrecargas são tentadas em ordem, a primeira correspondência vence (bem, não exatamente, mas em casos simples sem *args/**kwargs e ParamSpec isso é verdade):

      class Sub(Super):
          @overload
          def method(self, arg: Other | Sub) -> Sub: ...
          @overload
          def method(self, arg: Other | Super) -> Super: ...
      

    Mas eu simplesmente ignoraria o comentário e explicaria o problema:

    class Sub(Super):
        # The override is safe, but doesn't conform to the spec.
        # https://github.com/python/mypy/issues/12379
        @overload  # type: ignore[override]
        def method(self, arg: Other | Sub) -> Sub: ...
        @overload
        def method(self, arg: Super) -> Super: ...
    
    • 4

relate perguntas

  • Como divido o loop for em 3 quadros de dados individuais?

  • Como verificar se todas as colunas flutuantes em um Pandas DataFrame são aproximadamente iguais ou próximas

  • Como funciona o "load_dataset", já que não está detectando arquivos de exemplo?

  • Por que a comparação de string pandas.eval() retorna False

  • Python tkinter/ ttkboostrap dateentry não funciona quando no estado somente leitura

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve