如何将 "value" 属性强类型化为 str 或自定义类型?
How to strongly type the "value" attribute to be str or a custom type?
在严格类型检查模式下使用 Pylance (ms-python.vscode-pylance) VS Code 扩展时,我在以下代码的自定义枚举值上遇到类型错误:
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
类型。所以我的objective是强类型我的扩展Enum
的value
属性:
# python enum : https://docs.python.org/3/library/enum.html
from enum import Enum
class ANSICtrlSequence(Enum):
# basic control sequences
RESET = "3[m"
# full control sequences
PASSED = "3[1;4;38;5;76m"
FAILED = "3[1;5;38;5;197m"
我已经尝试过一些事情,例如按照指定 做 ANSICtrlSequence(str, Enum)
但没有成功。
我已经阅读了 class enum.pyi
我可以理解为什么值的类型是这样的:
class Enum(metaclass=EnumMeta):
name: str
value: Any
...
我找不到在 documentation or on 中的任何地方将我的值属性键入为 str 的方法。那有可能吗?有没有办法覆盖继承属性的类型?或者我是否需要扩展 Enum class 与例如可能是 StrEnum 的 IntEnum 的等价物?也许我需要编写自己的强类型枚举 class?有什么我遗漏的吗?
问题似乎并非完全 来自 Enum.value
,而是来自 str
作为 ctrlSequence
的可能类型。 Pylance 似乎检查 Union
中包含的所有类型是否具有 .value
属性,而对于 str
,当然,它没有 .value
所以 Pylance 没有不知道期望的类型(那是“未知”)。
我们可以在不使用 Enum
:
的情况下重现 similar“未知”错误
x = 5
print(x.value)
在你的情况下,在定义你的 Enum
时遵循 解决方案并从 str
继承仍然是必要的,因为这表明类型检查器(这里是 Pylance)你的 Enum .value
是 str
类型的。
所以,你肯定需要这个来强类型你的枚举:
class ANSICtrlSequence(str, Enum):
RESET = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[1;5;38;5;197m"
但是,它仍然显示为
Type of "value" is partially unknown
^ Type of "value" is "Any | Unknown*"
因为在Union[ANSICtrlSequence, str]
中,ANSICtrlSequence
的.value
的类型是Any
,str
的.value
的类型是Unknown .当您将 Union 的顺序反转为 Union[str, ANSICtrlSequence]
,然后变为
时,str
的这个问题就很明显了
Type of "value" is "Unknown | Any"
...表示“未知”与 str
相关联。基本上,我的观点是 你不应该专注于键入枚举的 .value
属性,因为问题在于包含 str
。如果您删除 Union
并仅使用 ANSICtrlSequence
:
,错误实际上会消失
class ANSICtrlSequence(str, Enum):
RESET = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[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)
, use isinstance(obj, classinfo)
:
class ANSICtrlSequence(str, Enum):
RESET = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[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
检查对象的类型,并且我的代码中没有出现枚举或联合与枚举的任何 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 = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[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
强制执行类型检查器(这里是 Pylance),ctrlSequence
是您的枚举类型,.value
确实是一个字符串。
在严格类型检查模式下使用 Pylance (ms-python.vscode-pylance) VS Code 扩展时,我在以下代码的自定义枚举值上遇到类型错误:
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
类型。所以我的objective是强类型我的扩展Enum
的value
属性:
# python enum : https://docs.python.org/3/library/enum.html
from enum import Enum
class ANSICtrlSequence(Enum):
# basic control sequences
RESET = "3[m"
# full control sequences
PASSED = "3[1;4;38;5;76m"
FAILED = "3[1;5;38;5;197m"
我已经尝试过一些事情,例如按照指定 ANSICtrlSequence(str, Enum)
但没有成功。
我已经阅读了 class enum.pyi
我可以理解为什么值的类型是这样的:
class Enum(metaclass=EnumMeta):
name: str
value: Any
...
我找不到在 documentation or on
问题似乎并非完全 来自 Enum.value
,而是来自 str
作为 ctrlSequence
的可能类型。 Pylance 似乎检查 Union
中包含的所有类型是否具有 .value
属性,而对于 str
,当然,它没有 .value
所以 Pylance 没有不知道期望的类型(那是“未知”)。
我们可以在不使用 Enum
:
x = 5
print(x.value)
在你的情况下,在定义你的 Enum
时遵循 str
继承仍然是必要的,因为这表明类型检查器(这里是 Pylance)你的 Enum .value
是 str
类型的。
所以,你肯定需要这个来强类型你的枚举:
class ANSICtrlSequence(str, Enum):
RESET = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[1;5;38;5;197m"
但是,它仍然显示为
Type of "value" is partially unknown
^ Type of "value" is "Any | Unknown*"
因为在Union[ANSICtrlSequence, str]
中,ANSICtrlSequence
的.value
的类型是Any
,str
的.value
的类型是Unknown .当您将 Union 的顺序反转为 Union[str, ANSICtrlSequence]
,然后变为
str
的这个问题就很明显了
Type of "value" is "Unknown | Any"
...表示“未知”与 str
相关联。基本上,我的观点是 你不应该专注于键入枚举的 .value
属性,因为问题在于包含 str
。如果您删除 Union
并仅使用 ANSICtrlSequence
:
class ANSICtrlSequence(str, Enum):
RESET = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[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)
, use isinstance(obj, classinfo)
:
class ANSICtrlSequence(str, Enum):
RESET = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[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
检查对象的类型,并且我的代码中没有出现枚举或联合与枚举的任何 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 = "3[m"
PASSED = "3[1;4;38;5;76m"
FAILED = "3[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
强制执行类型检查器(这里是 Pylance),ctrlSequence
是您的枚举类型,.value
确实是一个字符串。