Как избежать повторения кода в цикле, если аргумент представляет собой последовательность (список, кортеж), или пропустить цикл, но выполнить действие только один раз?
def foo(arg1,sequence=None):
# If possible, loop, else do it once
if isinstance(sequence,(list,tuple)):
for value in sequence:
do_something(arg1)
else:
do_something(arg1)
Действия, которые я выполняю в цикле for, намного длиннее, чем это, и мне было интересно, какой подход вы обычно используете, чтобы этого избежать, если вы его избегаете. Я часто сталкиваюсь с этой проблемой и не придумал ничего, чтобы ее «решить».
Обновлено: Вопрос не является дубликатом Как в Python определить, является ли объект итерируемым?, как предлагается. Я не хочу вводить другое условие. Я хочу избежать повторения.






Стандартизируйте цикл, который является случаем по умолчанию, и преобразуйте свой единственный случай в повторяемый:
if not isinstance(sequence, (list, tuple)):
sequence = [sequence]
for value in sequence:
do_something(value)
Единственный другой разумный способ, который я могу придумать, - это преобразовать все в последовательность, а затем безоговорочно выполнить итерацию. Это относительно часто можно увидеть в коде Python и часто извлекают во вспомогательную функцию.
if not isinstance(sequence, (list, tuple)):
sequence = [sequence]
for value in sequence:
...
Распространенный способ Python - «попросить прощения вместо разрешения». То есть попробуйте рассматривать его как повторяемый, а если это не удается, предположите, что это не
try:
for value in sequence:
do_something(arg1)
except TypeError:
do_something(arg1)
Я знаю, что это кажется нелогичным, когда вы переходите с другого языка, но это обычный способ сделать это в Python.
Если это приводит к повторению кода (а OP говорит, что кода там больше), то нет, это тоже не очень питонично.
@deceze: я видел шаблон в стандартных библиотеках Python, поэтому он должен быть достаточно питоническим. Если есть больше кода, OP может сделать из него функцию (что должно быть сделано в любом случае, независимо от того, какой подход он выберет)
С точки зрения разработка программного обеспечения было бы интересно разделить это на две функции:
def make_iterable(iterable):
if not isinstance(iteable, (list,tuple)):
return (iterable, )
return iterable
def foo(arg1 ,sequence=None):
for item in make_iterable(sequence):
do_something(arg1, item)Итак, теперь мы можем легко сделать итерируемыми больше вещей. Мы могли бы, например, вернуть пустой кортеж для None, так что None разрешен как способ избежать любой итерации:
def make_iterable(iterable):
if iterable is None:
return ()
if not isinstance(iteable, (list,tuple)):
return (iterable, )
return iterableТакже легко повторное использование вышеупомянутого метода во всех видах методов, которые позволяют вводить как один объект, так и итерацию.
Однако учтите, что с вышеизложенным могут быть некоторые проблемы. Некоторые типы являются итерируемыми, но сами по себе не являются элементами, которые вы хотите перебирать: например, string является итерируемым (вы можете перебирать его символы). В этом случае Как в Python определить, является ли объект итерируемым? завершится успешно, но «распаковывать» строку - не лучшая идея. Но вы, возможно, не захотите перебирать строку, когда вы называете ее как foo(4, 'foobar'), а рассматриваете ее как отдельный элемент.
В чем смысл вашей петли
for? Он не используетvalue, который переключается.