Is there a way in python to restrict generic types to ones that can be instantiated?
I'm looking for an equivalent to C#'s
where T : new()
I am already using type hints as follows
T = TypeVar("T", bound=Button)
And I'd like to know if there something like
T = TypeVar("T", bound=Button,new())
For example, given that Button is an abstract class (ABC) this code should create a menu composed of any subtype of 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
As it stands now, it allows calling the method with an abstract type Button, which fails at run time when I try to create instances of it.
I am using python 3.8.1 and VS Code with pylance
Edit: One of the answers suggested replacing the Generics by Protocol to make sure Buttons functions were implemented. While this prevents sending the abstract class, it allows sending classes that don't inherit from Button. I'm looking for away to enforce both restrictions.
Python is an interpreted, high-level, general-purpose programming language. C is a general-purpose, procedural computer programming language. Interpreted programs execute slower as compared to compiled programs. Compiled programs execute faster as compared to interpreted programs.
CPython is the reference implementation of the Python programming language. Written in C and Python, CPython is the default and most widely used implementation of the Python language. CPython can be defined as both an interpreter and a compiler as it compiles Python code into bytecode before interpreting it.
Python is an excellent tool enabling just that. It allows for focusing on the idea itself and not be bothered with boilerplate code and other tedious things. However, Python comes with a major drawback: It is much slower than compiled languages like C or C++.
Any code that you write using any compiled language like C, C++, or Java can be integrated or imported into another Python script. This code is considered as an "extension." A Python extension module is nothing more than a normal C library.
C++. Almost everything said for Java also applies for C++, just more so: where Python code is typically 3-5 times shorter than equivalent Java code, it is often 5-10 times shorter than equivalent C++ code! Anecdotal evidence suggests that one Python programmer can finish in two months what two C++ programmers can't complete in a year.
More difficult to write code in contrast to both Python and C++ due to complex syntax. C++ code is less complex than C but more complex in contrast to python. Easier to write code. Longer lines of code as compared to python. Longer lines of code as compared to python.
There is no direct equivalent in C++ to the Python 'isinstance' operator, but you can replicate the behavior by testing the result of a 'dynamic_cast':
C#'s System.Collections.Generic.List collection and Python's 'list' are very close equivalents. C#'s System.Collections.Generic.Dictionary collection and Python's 'dict' are very close equivalents. Python has a single comment format, starting with the '#' symbol.
I'm not familiar with this topic, but Protocol
might be the way to go here.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With