在严格类型检查模式下使用 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)
在您的情况下,请遵循 string-based enum解决方案并继承自
str
定义您的 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"
但是,它仍然显示为Type of "value" is partially unknown
^ Type of "value" is "Any | Unknown*"
因为在
Union[ANSICtrlSequence, str]
,.value
的类型为 ANSICtrlSequence
是 Any
和.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
时代码已经检查了 ctrlSequence
是 Enum
.有趣的是,有效的是改变检查类型的方式。而不是
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
...满足 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
...这再次满足 Pylance 并修复了错误:)
cast
强制执行 ctrlSequence
的类型检查器(这里是 Pylance)是您的 Enum 类型,而 .value
确实是一个字符串。
关于python - 如何将 "value"属性强类型为 str 或自定义类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68032592/