Питонский путь - не . Выберите один и позвольте вызывающей стороне предоставить правильный аргумент (ы):
# Iterable only: caller wraps the arguments
def for_each(iterable=None):
if iterable is None:
iterable = ()
# or just return now, if that's an option
for arg in iterable:
...
foreach((1,2,3))
# separate args: caller unpacks the arguments
def for_each(*args):
for arg in args:
...
x = [1,2,3]
for_each(*x)
Нет хорошего способа сделать это так, как вы хотите, потому что вы изначально пытаетесь угадать намерения звонящего. Вы должны посчитать количество аргументов, а затем вам нужно беспокоиться о таких типах, как str, которые выглядят как итерируемые, но не являются, или, возможно, так и должно быть.
Если это нужно сделать так, как вы хотите, ваш исходный пример будет настолько хорош, насколько вы можете, но он все еще несовершенен. Предположим, пользователь хочет обработать строку как в итерируемой; ваш подход все еще требует, чтобы они написали for_each (["foo"]), и в этом случае, зачем усложнять реализацию вашей функции без причины.