python 相当于 c# 其中 T : new()

Gon*_*n I 6 python generics bounded-types

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

我正在寻找与 C# 相当的东西

 where T : new()
Run Code Online (Sandbox Code Playgroud)

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

T = TypeVar("T", bound=Button)
Run Code Online (Sandbox Code Playgroud)

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

 T = TypeVar("T", bound=Button,new())
Run Code Online (Sandbox Code Playgroud)

例如,假设 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
Run Code Online (Sandbox Code Playgroud)

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

我正在使用 python 3.8.1 和 VS Code 以及 pylance

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

Niz*_*ziL 4

我不熟悉这个主题,但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()
Run Code Online (Sandbox Code Playgroud)