Skip to content

Instantly share code, notes, and snippets.

@JotaRata
Last active August 6, 2023 05:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JotaRata/fd5dd8564ba8bb1d877070f3c03941da to your computer and use it in GitHub Desktop.
Save JotaRata/fd5dd8564ba8bb1d877070f3c03941da to your computer and use it in GitHub Desktop.
Python Generic List
'''
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()
@JotaRata
Copy link
Author

JotaRata commented Aug 6, 2023

You may think this solution is not elegant, but is exactly how the typing library works tho

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment