如何根据枚举类型重载python类方法

Posted

技术标签:

【中文标题】如何根据枚举类型重载python类方法【英文标题】:How do you overload python class method based on Enum type 【发布时间】:2021-12-25 06:08:03 【问题描述】:

我正在尝试为使用重载类型装饰器的类创建一个 python 方法。我希望根据传递的 Enum 类型重载该方法。例如,

class GetPortType(enum.Enum):
    DIFF_1: "Diff1"
    DIFF_2: "Diff2"
    SAME_1: "Same1"
    SAME_2: "Same2"

class Port:
...
    @typing.overload
    def get_port_on_type(self, type: GetPortType.DIFF_1, num: int, skip: Optional[List]):
        statement1
        statement2
        return [values]

    @typing.overload
    def get_port_on_type(self, type: GetPortType.DIFF_2, num: int, skip: Optional[List]):
        statement3
        statement4
        return [values]

    @typing.overload
    def get_port_on_type(self, type: GetPortType.SAME_1, num: int, skip: Optional[List]):
        statement1
        statement3
        return [values]

    @typing.overload
    def get_port_on_type(self, type: GetPortType.SAME_2, num: int, skip: Optional[List]):
        statement2
        statement4
        return [values]

我如何实现这一目标?我应该为所有这些情况的枚举和返回类型创建一个“def __ new __(self, value):”方法吗?

编辑:我想知道我们是否可以对 Metaclass 做一些事情,比如返回值类型?哪个可能是这个元类的属性?

@property
def type(self):
    return type(self.value)

""" changing the type annotation """
type: GetPortType.SAME_2.type

【问题讨论】:

你试过typing.Literal。例如,最后一个的类型是Literal[GetPortType.SAME_2] 我想你不明白,typing.overload 不会让你实际使用方法重载。它仅用于类型注释 type: GetPortType.DIFF_2 那不是类型 @FrankYellin 仔细观察,OP 似乎认为您可以根据重载签名拥有 不同的实现 @juanpa.arrivillaga 哎呀。我以为他们只是在问一个打字问题。对不起。 【参考方案1】:

您似乎误解了typing.overload 的作用。它让您定义在不同情况下运行的不同版本的代码。相反,它用于类型提示,表示单个实现支持多种类型组合。函数的任何重载定义都不会运行,它们为稍后出现的函数的真实版本添加更好的类型提示。

这是一个例子given in the documentation:

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

请注意,... 省略号文字是您可能实际放入此代码的内容,它并不代表仅用于文档的内容。在那些 @overload 装饰的函数中不需要主体,因为它们从不运行。 ... 文字似乎已经出现在类型提示爱好者中,作为函数存根的首选主体,而不是 pass(至少曾经是函数的首选“什么都不做”主体)。

如果您确实需要一个能够根据参数类型运行不同版本的函数的装饰器,您可以使用functools.singledispatch。但它分派实际类型,而不是您想要的文字值(例如 Enum 的特定实例)。

解决问题的简单方法是编写一组 if/elif/else 块,以便在您进入函数后将调用分开:

def get_port_on_type(self, type: GetPortType, num: int, skip: Optional[List]):
    if type == GetPortType.DIFF_1:
        do_stuff_1()
    elif type == GetPortType.DIFF_2:
        do_stuff_2()
    elif type == GetPortType.SAME_1:
        do_stuff_3()
    else: # type == GetPortType.SAME_2:
        do_stuff_4()

从 Python 3.10 开始,您可以使用新的 match and case statements 来做与上面的 if/elif/else 代码链基本相同的事情,语法稍微好一点,但我我仍在使用 3.9,我没有信心为您编写一个我无法测试的示例(有关新语句类型的教程,请参阅 PEP 636)。

【讨论】:

以上是关于如何根据枚举类型重载python类方法的主要内容,如果未能解决你的问题,请参考以下文章

C#如何将枚举类(enum)型转换成字符(string)类型

如何在 C# 中为枚举重载运算符?

枚举类型取值helper类

006.值类型引用类型枚举类型字符串冒泡排序

java枚举类型

java枚举类型