Первая итерация цикла "For"
Приветствия pyc-sires и py-ladies,
Я хотел бы узнать, есть ли элегантный pythonic способ выполнения некоторой функции на первой итерации цикла.
Единственная возможность, о которой я могу думать, это:
first = True
for member in something.get():
if first:
root.copy(member)
first = False
else:
somewhereElse.copy(member)
foo(member)
Ответы
Ответ 1
У вас есть несколько вариантов дизайна шаблона Head-Tail.
seq= something.get()
root.copy( seq[0] )
foo( seq[0] )
for member in seq[1:]:
somewhereElse.copy(member)
foo( member )
Или это
seq_iter= iter( something.get() )
head = seq_iter.next()
root.copy( head )
foo( head )
for member in seq_iter:
somewhereElse.copy( member )
foo( member )
Люди скулят, что это как-то не "СУХОЙ", потому что "избыточный код foo (member)". Это смехотворное требование. Если это так, то все функции можно использовать только один раз. Какой смысл определять функцию, если у вас есть только одна ссылка?
Ответ 2
Что-то вроде этого должно работать.
for i, member in enumerate(something.get()):
if i == 0:
# Do thing
# Code for everything
Однако я бы настоятельно рекомендовал подумать о вашем коде, чтобы увидеть, действительно ли вам нужно это делать, потому что это своего рода "грязный". Лучше было бы получить элемент, который требует специальной обработки спереди, а затем выполнять регулярную обработку для всех остальных в цикле.
Единственная причина, по которой я не мог этого сделать, - это получить большой список, который вы получите из выражения генератора (который вы не хотели бы получать из-за фронта, потому что он не вписывался в память) или аналогичные ситуации.
Ответ 3
как насчет:
my_array = something.get()
for member in my_array:
if my_array.index(member) == 0:
root.copy(member)
else:
somewhereElse.copy(member)
foo(member)
или возможно:
for index, member in enumerate(something.get()):
if index == 0:
root.copy(member)
else:
somewhereElse.copy(member)
foo(member)
Документация индексный метод.
Ответ 4
Я думаю, что это довольно элегантно, но, возможно, слишком запутанно для того, что он делает...
from itertools import chain, repeat, izip
for place, member in izip(chain([root], repeat(somewhereElse)), something.get()):
place.copy(member)
foo(member)
Ответ 5
Это работает:
for number, member in enumerate(something.get()):
if not number:
root.copy(member)
else:
somewhereElse.copy(member)
foo(member)
В большинстве случаев я предлагаю просто перебирать whatever[1:]
и делать корневую вещь вне цикла; что обычно более читаемо. Разумеется, зависит от вашего прецедента.
Ответ 6
Если something.get() итерирует что-то, вы можете сделать это также следующим образом:
root.copy(something.get())
for member in something.get():
# the rest of the loop
Ответ 7
Здесь я могу прийти с питонической идиомой, которая может выглядеть "pertty". Хотя, скорее всего, я бы использовал форму, которую вы предложили, задав вопрос, просто чтобы код оставался более очевидным, хотя и менее элегантным.
def copy_iter():
yield root.copy
while True:
yield somewhereElse.copy
for member, copy in zip(something.get(), copy_iter()):
copy(member)
foo(member)
(извините - первый, который я опубликовал, до редактирования, форма не сработала, я забыл фактически получить итератор для объекта "copy" )
Ответ 8
Как насчет использования iter
и потребления первого элемента?
Изменить: Возвращаясь к вопросу о OP, есть общая операция, которую вы хотите выполнить для всех элементов, а затем одну операцию, которую вы хотите выполнить для первого элемента, а другая - на остальное.
Если это всего лишь один вызов функции, я бы просто написал его дважды. Это не закончит мир. Если это более активно, вы можете использовать декоратор, чтобы обернуть свою "первую" функцию и "отдохнуть" с помощью общей операции.
def common(item):
print "common (x**2):", item**2
def wrap_common(func):
"""Wraps `func` with a common operation"""
def wrapped(item):
func(item)
common(item)
return wrapped
@wrap_common
def first(item):
"""Performed on first item"""
print "first:", item+2
@wrap_common
def rest(item):
"""Performed on rest of items"""
print "rest:", item+5
items = iter(range(5))
first(items.next())
for item in items:
rest(item)
Вывод:
first: 2
common (x**2): 0
rest: 6
common (x**2): 1
rest: 7
common (x**2): 4
rest: 8
common (x**2): 9
rest: 9
common (x**2): 16
или вы можете сделать фрагмент:
first(items[0])
for item in items[1:]:
rest(item)
Ответ 9
Я думаю, что первое решение S.Lott - лучшее, но есть другой выбор, если вы используете довольно недавний python ( >= 2.6, я думаю, поскольку izip_longest пока недоступен до этой версии), что позволяет делать разные вещи для первого элемента и последовательные, и могут быть легко модифицированы для выполнения отдельных операций для 1-го, 2-го, 3-го элементов... также.
from itertools import izip_longest
seq = [1, 2, 3, 4, 5]
def headfunc(value):
# do something
print "1st value: %s" % value
def tailfunc(value):
# do something else
print "this is another value: %s" % value
def foo(value):
print "perform this at ANY iteration."
for member, func in izip_longest(seq, [headfunc], fillvalue=tailfunc):
func(member)
foo(member)
Ответ 10
Вы не можете сделать root.copy(something.get())
перед циклом?
EDIT: Извините, я пропустил второй бит. Но вы получаете общую идею. В противном случае перечислите и проверьте 0
?
EDIT2: Хорошо, избавился от глупой второй идеи.
Ответ 11
Я не знаю Python, но я использую почти точный шаблон вашего примера.
То, что я делаю, также делает условие if
наиболее частым, поэтому обычно проверяйте if( first == false )
Зачем? для длинных циклов сначала будет истинно только один раз и будет ложным все другие времена, что означает, что во всех циклах, кроме первого, программа будет проверять состояние и перейти к части else.
Проверяя, что первое было ложным, будет только один переход к части else. Я не знаю, добавляет ли это эффективность вообще, но я все равно делаю это, просто чтобы быть в покое с моим внутренним ботаником.
PS: Да, я знаю, что при входе в часть if он также должен перепрыгивать через else, чтобы продолжить выполнение, поэтому, вероятно, мой способ сделать это бесполезен, но он чувствует себя хорошо.: D
Ответ 12
Ваш вопрос противоречив. Вы говорите: "делайте только что-то на первой итерации", когда на самом деле вы говорите что-то другое на первых и последующих итерациях. Вот как я попытался бы это сделать:
copyfn = root.copy
for member in something.get():
copyfn(member)
foo(member)
copyfn = somewhereElse.copy