如何将“值”属性强输入为 str 或自定义类型?

问题描述

在严格类型检查模式下使用 Pylance (ms-python.vscode-pylance) VS Code 扩展时,我的自定义 Enum 值出现以下代码的类型错误

def println_ctrl_sequence(message: str,ctrlSequence: Union[ANSICtrlSequence,str]):
    """
    This function is use with  terminals to print the message
    with colors specified by a,ANSI control sequence that 
    can be either a str or a console.ANSICtrlSequence object.
    """
    if type(ctrlSequence) == ANSICtrlSequence:
        ctrlSequenceStr: str = ctrlSequence.value
    else:
        ctrlSequenceStr = ctrlSequence
    
    print("%s%s%s" % (
        ctrlSequenceStr,message,ANSICtrlSequence.RESET.value
    ))

ctrlSequenceStr: str = ctrlSequence.value 行检测到类型错误,因为 ctrlSequence.value 被检测为 Any | UnkNown 类型。所以我的目标是强类型扩展 valueEnum 属性

# python enum : https://docs.python.org/3/library/enum.html 
from enum import Enum

class ANSICtrlSequence(Enum):

    # basic control sequences
    RESET = "\033[m" 

    # full control sequences
    PASSED = "\033[1;4;38;5;76m" 
    Failed = "\033[1;5;38;5;197m" 

我尝试过诸如按照指定的 here in "String-based enum in Python" Q&A 执行 ANSICtrlSequence(str,Enum) 之类的事情,但没有成功。

我已经阅读了 enum.pyi 类,我可以理解为什么值的类型是这样的:

class Enum(Metaclass=EnumMeta):
    name: str
    value: Any
    ...

我找不到将我的 value 属性键入为 str 在 documentationStackOverflow 上的任何位置的方法。那么有可能吗?有没有办法覆盖继承属性的类型?或者我是否需要使用例如 IntEnum 的等效项来扩展 Enum 类,例如可以是 StrEnum ?也许我需要编写自己的强类型 Enum 类?有什么我错过的吗?

解决方法

问题似乎不是完全来自 Enum.value,而是来自包含 str 作为 ctrlSequence 的可能类型。 Pylance 似乎会检查 Union 中包含的所有类型是否都具有 .value 属性,而对于 str,当然它没有 .value 所以 Pylance 没有不知道期望什么类型(那是“未知”)。

我们可以在不使用 Enum 的情况下重现类似“未知”错误:

x = 5
print(x.value)

similar error without enum

就您而言,在定义您的 str 时遵循 string-based enum 解决方案并从 Enum 继承仍然是必要的,因为这向类型检查器(此处为 Pylance)表明您的 Enum .value 属于 str 类型。

所以,你肯定需要这个来强输入你的枚举:

class ANSICtrlSequence(str,Enum):
    RESET = "\033[m" 
    PASSED = "\033[1;4;38;5;76m" 
    FAILED = "\033[1;5;38;5;197m" 

但是,它仍然显示为

“值”的类型部分未知
^ "value" 的类型是 "Any | Unknown*"

因为在Union[ANSICtrlSequence,str]中,.value的{​​{1}}类型是ANSICtrlSequenceAny的{​​{1}}类型是Unknown。当您将联合的顺序颠倒为 .value 时,str 的这个问题很明显,然后变成

“值”的类型是“未知 | 任意”

...表示“未知”与 str 相关联。基本上,我的观点是您不应该专注于输入枚举的 Union[str,ANSICtrlSequence] 属性,因为问题在于包含 str。如果您删除 .value 并仅使用 str,该错误实际上会消失:

Union

...首先表明您的 ANSICtrlSequence 没有任何问题。

但我明白为什么代码中有一个联盟。不幸的是,Pylance 没有。它不明白当代码到达 class ANSICtrlSequence(str,Enum): RESET = "\033[m" PASSED = "\033[1;4;38;5;76m" FAILED = "\033[1;5;38;5;197m" def println_ctrl_sequence(message: str,ctrlSequence: ANSICtrlSequence): # Pylance does not complain here ctrlSequenceStr: str = ctrlSequence.value 时,代码已经检查 EnumctrlSequence.value

有趣的是,有效的是改变检查类型的方式。使用 type(obj) 代替 isinstance(obj,classinfo)

ctrlSequence

no errors with isinstance

...满足 Pylance 并修复错误:)

我希望这不是“它适用于我的环境”的情况,但我在检查对象类型时几乎总是使用 Enum 而不是 class ANSICtrlSequence(str,ctrlSequence: Union[ANSICtrlSequence,str]): if isinstance(ctrlSequence,ANSICtrlSequence): ctrlSequenceStr: str = ctrlSequence.value else: ctrlSequenceStr = ctrlSequence ,并且我的代码中没有任何关于 Enums 或 Unions with Enums 的 Pylance 错误。我不知道 Pylance 是如何工作的,但这里有一个关于该主题的相关问答:What are the differences between type() and isinstance()?

如果您真的需要使用isinstance,那么您可以使用typing.cast,其中:

将值转换为类型。

这将返回未更改的值。对于类型检查器,这表明返回值具有指定类型,但在运行时我们故意不检查任何内容(我们希望尽可能快)。

type

no errors by using cast

...这再次满足 Pylance 并修复了错误:) type(ctrlSequence) 强制执行类型检查器(这里是 Pylance),from typing import Union,cast class ANSICtrlSequence(str,str]): if type(ctrlSequence) == ANSICtrlSequence: ctrlSequence = cast(ANSICtrlSequence,ctrlSequence) ctrlSequenceStr: str = ctrlSequence.value else: ctrlSequenceStr = ctrlSequence 是您的 Enum 类型,而 cast确实是一个字符串。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...