python - 如何将 "value"属性强类型为 str 或自定义类型?

标签 python visual-studio-code enums python-typing pylance

在严格类型检查模式下使用 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 .所以我的目标是强输入 value我扩展的属性 Enum :
# 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" 
我尝试过诸如做 ANSICtrlSequence(str, Enum) 之类的事情。如指定 here in "String-based enum in Python" Q&A没有成功。
我读过课enum.pyi我可以理解为什么值的类型是这样的:
class Enum(metaclass=EnumMeta):
    name: str
    value: Any
    ...
我找不到一种方法将我的 value 属性输入为 str 在 documentation 中的任何位置或在 StackOverflow .那么有可能吗?有没有办法覆盖继承属性的类型 ?或者我是否需要使用例如 IntEnum 的等效项来扩展 Enum 类,例如可以是 StrEnum ?也许我需要编写自己的强类型 Enum 类?有什么我错过的吗?

最佳答案

看来问题不完全来自Enum.value但从包括 str作为 ctrlSequence 的可能类型. Pylance 似乎会检查 Union 中是否包含所有类型有一个 .value属性,以及 str ,当然,它没有.value所以 Pylance 不知道期望什么类型(即“未知”)。
我们可以在不使用 Enum 的情况下重现类似的“未知”错误。 :

x = 5
print(x.value)
similar error without enum
在您的情况下,请遵循 string-based enum解决方案并继承自 str定义您的 Enum 时仍然是必要的,因为这向类型检查器(这里是 Pylance)表明您的 Enum .valuestr -类型。
所以,你绝对需要这个来强输入你的枚举:
class ANSICtrlSequence(str, Enum):
    RESET = "\033[m" 
    PASSED = "\033[1;4;38;5;76m" 
    FAILED = "\033[1;5;38;5;197m" 
但是,它仍然显示为

Type of "value" is partially unknown
^ Type of "value" is "Any | Unknown*"


因为在 Union[ANSICtrlSequence, str].value的类型为 ANSICtrlSequenceAny.value的类型为 str是未知的。此问题与 str当您将联合的顺序颠倒为 Union[str, ANSICtrlSequence] 时很明显,然后变成

 Type of "value" is "Unknown | Any"


...表明“未知”与 str 相关联.基本上,我的观点是你不应该专注于输入 .value枚举的属性,因为问题在于包含 str .如果您删除 Union,该错误实际上会消失。只需使用 ANSICtrlSequence :
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
...这表明您的 Enum 没有任何问题首先。
但我明白为什么代码中有一个 Union 。不幸的是,Pylance 没有。它不明白当代码到达 ctrlSequence.value 时代码已经检查了 ctrlSequenceEnum .
有趣的是,有效的是改变检查类型的方式。而不是 type(obj) , 使用 isinstance(obj, classinfo) :
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: Union[ANSICtrlSequence, str]):
    if isinstance(ctrlSequence, ANSICtrlSequence):
        ctrlSequenceStr: str = ctrlSequence.value
    else:
        ctrlSequenceStr = ctrlSequence
no errors with isinstance
...满足 Pylance 并修复错误:)
我希望这不是“它适用于我的环境”的情况,但我几乎总是使用 isinstance而不是 type在检查对象的类型时,我的代码中的 Enums 或 Unions with Enums 没有出现任何 Pylance 错误。我不知道 Pylance 是如何工作的,但这里有一个关于该主题的相关问答:What are the differences between type() and isinstance()?
如果你真的需要使用type(ctrlSequence) ,那么你可以使用 typing.cast , 哪个:

Cast a value to a type.

This returns the value unchanged. To the type checker this signals that the return value has the designated type, but at runtime we intentionally don’t check anything (we want this to be as fast as possible).

from typing import Union, cast

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: Union[ANSICtrlSequence, str]):
    if type(ctrlSequence) == ANSICtrlSequence:
        ctrlSequence = cast(ANSICtrlSequence, ctrlSequence)
        ctrlSequenceStr: str = ctrlSequence.value
    else:
        ctrlSequenceStr = ctrlSequence
no errors by using cast
...这再次满足 Pylance 并修复了错误:) cast强制执行 ctrlSequence 的类型检查器(这里是 Pylance)是您的 Enum 类型,而 .value确实是一个字符串。

关于python - 如何将 "value"属性强类型为 str 或自定义类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68032592/

相关文章:

python - 如何从 Pandas DateTime Index 中删除时间值?

python - Selenium、Python,是否可以缩小定位器范围?

visual-studio-code - VS代码: disable linking between open files and explorer

c++ - 哪些枚举值在 C++14 中是未定义的行为,为什么?

java - 按字母顺序对 Enum.values() 进行排序,并将它们添加到 Spinner ArrayAdapter

python - 为什么 Python list() 并不总是具有相同的顺序?

python - 单元测试sqlalchemy BinaryExpression

c++11 - 远程GDB session "Command Aborted"

jquery - 在 VS Code 的 TypeScript 中使用 jQuery

c# - 当它是泛型时是否可以转换为枚举?