Mypy - 在替代分支中分配不同值时分配中的不兼容类型

问题描述 投票:0回答:2

我想知道为什么我在这里得到

Incompatible types in assignment

from typing import cast

import pyvisa
from pyvisa.constants import InterfaceType
from pyvisa.resources import GPIBInstrument, TCPIPInstrument


class Instrument:
    resource_manager = pyvisa.ResourceManager()

    def __init__(self, resource: str):
        self.resource = self.resource_manager.open_resource(resource_name=resource)
        if self.resource.interface_type == InterfaceType.tcpip:
            self.instance: TCPIPInstrument = cast(TCPIPInstrument, resource)
        elif self.resource.interface_type == InterfaceType.gpib:
            self.instance: GPIBInstrument = cast(GPIBInstrument, resource)
        else:
            raise TypeError(f"Unsupported resource interface type: {self.resource.interface_type}")

Incompatible types in assignment (expression has type "GPIBInstrument", variable has type "TCPIPInstrument")

self.instance
在 vscode 中正确获取类型
instance: TCPIPInstrument | GPIBInstrument
.

我正在使用 python 3.11.3 和 mypy 1.2.0.

链接 到具有相同问题的要点,但代码略有不同,因为我无法在操场上安装 pyvisa。

从评论中发现代码中的一些问题,这里是更正确的代码,但仍然有同样的问题。

from typing import cast

import pyvisa
from pyvisa.constants import InterfaceType
from pyvisa.resources import GPIBInstrument, TCPIPInstrument


class Instrument:
    resource_manager = pyvisa.ResourceManager()

    def __init__(self, resource_name: str):
        self.resource = self.resource_manager.open_resource(resource_name=resource_name)
        if self.resource.interface_type == InterfaceType.tcpip:
            self.instance = cast(TCPIPInstrument, self.resource)
        elif self.resource.interface_type == InterfaceType.gpib:
            self.instance = cast(GPIBInstrument, self.resource)
        else:
            raise TypeError(f"Unsupported resource interface type: {self.resource.interface_type}")
python mypy
2个回答
1
投票

self.instance
只能有一个类型,在第一次声明时绑定;当您为变量分配新值时,mypy 不会扩大变量的类型(实际上,声明类型的部分目的是防止您在不同的逻辑分支中不小心混合单个变量的类型)。听起来 VSCode 插件的类型检查器做了一些不同的事情,它自动将类型推断为联合;如果你做了类似的事情,它可能会做同样的事情:

foo = "123"  # type is str
foo = 123    # type is now str|int I guess?

出于 mypy 的目的,如果您希望变量的类型是联合,则需要在首次声明时明确指定:

        if self.resource.interface_type == InterfaceType.tcpip:
            self.instance: GPIBInstrument | TCPIPInstrument = cast(TCPIPInstrument, resource)
        elif self.resource.interface_type == InterfaceType.gpib:
            self.instance = cast(GPIBInstrument, resource)
        else:
            raise TypeError(f"Unsupported resource interface type: {self.resource.interface_type}")

0
投票

Mypy 从它看到的第一个赋值中推断变量的类型(与此处的注释一致)。

如果你在另一个语句中分配了一个不相关类型的值,这是一个类型错误。

看起来这两种类型并非完全无关。您可以通过在第一次赋值之前声明变量的类型来教 Mypy,作为两种类型的联合或作为公共超类型。

© www.soinside.com 2019 - 2024. All rights reserved.