Just looking into the standard library, you're using the most common method.
For instance in heapq(1) (2) (3), bisect (1) (2), itertools (1):
def merge(*iterables, key=None, reverse=False):
'''Merge multiple sorted inputs into a single sorted output.
Similar to sorted(itertools.chain(*iterables)) but returns a generator,
does not pull the data into memory all at once, and assumes that each of
the input streams is already sorted (smallest to largest).
>>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))
[0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
If *key* is not None, applies a key function to each element to determine
its sort order.
>>> list(merge(['dog', 'horse'], ['cat', 'fish', 'kangaroo'], key=len))
['dog', 'cat', 'fish', 'horse', 'kangaroo']
'''
# skipping some lines
if key is None:
...
# skipping the rest
If you want to type it explicitly, just create a Union with Union[Callable, None] or Callable | None if using python >= 3.10.
You should check against None with v is None not v == None.
If possible, type your Callable otherwise it defaults to Callable[..., Any].
And finally also if possible type your return value(s) where I've put <idk> markers.
def myfunc(x: int = 0, metric_func: Callable[[int, int], <idk>] | None = None) -> list[<idk>]:
'''Type "None" cannot be assigned to type "function"'''
ret = []
if metric_func is None:
return ret
for i in range(10):
ret.append(metric_func(x, i))
return ret
lambda arg0, arg1: 1?metric_funcisn't provided? That seems strange. (Also look attyping.Optional.)Noneis actually ok, just add proper type hint likeOptional[Callable]orCallable | None