I'm curious if I could augment/extend the functionality of a base function using functools
techniques.
I'm putting together a module with many methods returning generators, and I'm looking for an effective way to dispatch them (?) and also provide the ability to return list without modifying the underlying code.
For example, I might have a simple function which returns a generator. I'd like to extend this function to also have an argument which allows the user to return a list as well.
The following works:
from typing import (
Union,
Generator,
List,
Literal,
)
from functools import wraps
from multimethod import multimethod
# already exists
def base_func(
a: int,
b: int,
) -> Generator:
assert b > a
for i in range(a, b):
yield i
#newly created
def extended_func(
a: int,
b: int,
return_as_list: bool,
) -> Union[Generator, List]:
gen = base_func(a, b)
return list(gen) if return_as_list else gen
This seems messy, or at least I'm wondering if it could be done more effectively using dispatching, since I'd like to avoid creating a completely new function.
I scratched together the code below, which does not work (it returns TypeError: type 'bool' is not an acceptable base type
), but might be able to get across what I'm trying to do. I know at this point it might obfuscate the original purpose of the function, but I guess I'm just trying to figure out if it's even possible for my own edification.
## decorator
def as_list(func):
"""
convert generator to list
"""
@wraps(func)
def wrapper(*args, **kwargs):
return list(func(*args, **kwargs))
return wrapper
@multimethod
def test_func(
a: int,
b: int,
return_as_list: Literal[False],
) -> Generator[int, None, None]:
assert b > a
for i in range(a, b):
yield i
@test_func.register
@as_list
def _(
a: int,
b: int,
return_as_list: Literal[True],
):
...