首页 > 解决方案 > python相当于c# where T : new()

问题描述

python中有没有办法将泛型类型限制为可以实例化的类型?

我正在寻找与 C# 的等价物

 where T : new()

我已经在使用如下类型提示

T = TypeVar("T", bound=Button)

我想知道是否有类似的东西

 T = TypeVar("T", bound=Button,new())

例如,假设 Button 是一个抽象类 (ABC),此代码应创建一个由 Button 的任何子类型组成的菜单

class Button(ABC):
    def __init__(self) -> None:
        self._name = ""
    @abstractmethod
    def show(self) -> None:
        pass
    def set_name(self, value:str) -> None:
        self._name = value

class SquareButton(Button):
    def show(self) -> None:
        print("[",self._name,"]")

class CircleButton(Button):
    def show(self) -> None:
        print("(",self._name,")")

T = TypeVar("T", bound=Button) # restricting type here

class MenuBuilder:
    def build(self,class_type: Type[T]) -> None:
        pb1: Button = class_type()
        pb2: Button = class_type()
        pb3: Button = class_type()
        pb1.set_name("button1")
        pb2.set_name("button2")
        pb3.set_name("button3")
        pb1.show(); pb2.show(); pb3.show()

#main
mb: MenuBuilder = MenuBuilder()
mb.build(Button) # fails at run time - I want a pre-run error here
mb.build(CircleButton) # OK

就目前而言,它允许使用抽象类型 Button 调用该方法,当我尝试创建它的实例时,该方法在运行时失败。

我正在使用 python 3.8.1 和带有 pylance 的 VS Code

编辑:答案之一建议通过协议替换泛型以确保实现按钮功能。虽然这会阻止发送抽象类,但它允许发送不继承自 Button 的类。我正在寻找执行这两个限制的方法。

标签: pythongenericsbounded-types

解决方案


我不熟悉这个话题,但Protocol可能是去这里的方式。

from typing import Protocol


class Button(Protocol):
    def show(self) -> None:
        ...

    def set_name(self, value: str) -> None:
        ...


class BaseButton(object):
    def __init__(self) -> None:
        self._name = ""

    def set_name(self, value:str) -> None:
        self._name = value


class SquareButton(BaseButton):
    def show(self) -> None:
        print("[",self._name,"]")


class CircleButton(BaseButton):
    def show(self) -> None:
        print("(",self._name,")")


class MenuBuilder:
    def build(self, class_type: Type[Button]) -> None:
        pb1: Button = class_type()
        pb2: Button = class_type()
        pb3: Button = class_type()
        pb1.set_name("button1")
        pb2.set_name("button2")
        pb3.set_name("button3")
        pb1.show()
        pb2.show()
        pb3.show()

推荐阅读