Last active
August 6, 2023 05:19
-
-
Save JotaRata/fd5dd8564ba8bb1d877070f3c03941da to your computer and use it in GitHub Desktop.
Python Generic List
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
C# like generic lists for python! | |
Description | |
A cool trick that uses a singleton variable called "List" which is an instance of a "hidden" class _GenericList | |
this class defines a __getitem__ method that returns a type object that internally stores the type given by the getter | |
because it is a type object you can instanstiate in python using curly braces, hence behaving exactly like a normal class | |
The class _GenericList also returns a regular list instance if no type were provided, this is done by defining the __call__ method | |
Usage: | |
Import this module | |
Make sure the variable List is set before using it | |
Create a generic list by putting the desired type inside square brackets | |
``` | |
l = List[int](1,2,3) | |
``` | |
Append/Insert methods work as well | |
``` | |
l = List[str]() | |
l.append('Hello') | |
``` | |
Attempts of adding an element of a different type will result in an Error | |
``` | |
l = List[int]() | |
l.append('Hello') # AssertionError | |
``` | |
Downsides: | |
Type checking occurs at runtime which makes the process slower | |
''' | |
class _GenericList: | |
def __getitem__(self, _type): | |
assert type(_type) is type | |
class ListWrapper(list): | |
def __init__(self, *args): | |
assert all(isinstance(item, _type) for item in args) | |
super().__init__(args) | |
def append(self, __object) -> None: | |
assert isinstance(__object, _type) | |
super().append(__object) | |
def insert(self, __index, __object): | |
assert isinstance(__object, _type) | |
super().insert(__index, __object) | |
def __add__(self, _value): | |
assert isinstance(_value, type(self)) | |
super().__add__(_value) | |
def __setitem__(self, __key, __value): | |
if type(__key) is int: | |
assert isinstance(__value, _type) | |
elif type(__key) is slice: | |
assert isinstance(__value, type(self)) \ | |
or all(isinstance(value, _type) for value in __value) | |
else: raise IndexError(type(__key).__name__) | |
super().__setitem__(__key, __value) | |
def __repr__(self) -> str: | |
return f'List({_type.__name__})' + super().__repr__() | |
return ListWrapper | |
def __call__(self, *args): | |
return list(args) | |
def __repr__(self): | |
return 'List' | |
List = _GenericList() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You may think this solution is not elegant, but is exactly how the typing library works tho