Custom String Formatter
For the second point, since it's easier, typing has an Any:

from typing import List, Any
. . ., variables: List[Any], . . .


For the first, you're just doing a reduction over variables:

from typing import List, Any
from functools import reduce


def format_string(string: str, variables: List[Any]) -&gt; str:
    return reduce(lambda s, val: s.replace("[*]", str(val), 1), variables, string)


Although really, in a real use case, I'd still split this over three lines for clarity:

def format_string(string: str, variables: List[Any]) -&gt; str:
    return reduce(lambda s, val: s.replace("[*]", str(val), 1),
                  variables, 
                  string)


And honestly, I might just make that function var-arg instead of grouping things in a list to make it consistent with other format functions:

def format_string(string: str, *variables: Any) -&gt; str:
    return reduce(lambda s, val: s.replace("[*]", str(val), 1), variables, string)

&gt;&gt;&gt; format_string("[*] Hello [*]", 1, 2)
'1 Hello 2'


Note that when annotating a a var-arg parameter, you annotate the type of each element and ignore the type of the wrapping container (a tuple iirc). That means it's *variables: Any, not *variables: Tuple[... Any].



Of course though, whether or not this is better is a matter of taste, but this is the ideal use-case for reduce. Whenever you want to constantly reassign one thing in a simple loop, reduce is likely a good tool to look at.