Я хотел бы запросить, существует ли изящный pythonic способ выполнить некоторую функцию на первом повторении цикла. Единственная возможность, о которой я могу думать:
first = True
for member in something.get():
if first:
root.copy(member)
first = False
else:
somewhereElse.copy(member)
foo(member)
У вас есть несколько вариантов для шаблона проектирования Голова-Хвост .
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) "код. Это нелепое заявление. Если бы это было так, то все функции можно было бы использовать только один раз. Какой смысл определять функцию, если у вас может быть только одна ссылка?
Здесь я мог бы использовать идиому Pythonic, которая может выглядеть "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)
(извините, первая, которую я опубликовал, перед редактированием, форма не будет работать, я забыл получить итератор для объекта «копия»)
как насчет:
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)
Документация index-method .
Что-то вроде этого должно сработать.
for i, member in enumerate(something.get()):
if i == 0:
# Do thing
# Code for everything
Однако я настоятельно рекомендую подумать о вашем коде, чтобы увидеть, действительно ли вам нужно делать это таким образом, потому что это своего рода "грязный". Лучше было бы заранее получить элемент, требующий особой обработки, а затем выполнять регулярную обработку для всех остальных в цикле.
Единственная причина, по которой я мог не делать этого таким образом, - это большой список, в котором вы будете получение из выражения генератора (которое вы не хотели бы получать заранее, потому что оно не помещается в памяти) или аналогичные ситуации.
Я думаю, это довольно элегантно, но, возможно, слишком запутано для того, что оно делает ...
from itertools import chain, repeat, izip
for place, member in izip(chain([root], repeat(somewhereElse)), something.get()):
place.copy(member)
foo(member)
Разве вы не можете выполнить root.copy (something.get ())
перед циклом?
РЕДАКТИРОВАТЬ: Извините, я пропустил второй бит . Но вы поняли общую идею. В противном случае выполните перечисление и проверьте наличие 0
?
EDIT2: Хорошо, избавился от второй глупой идеи.
Если something.get () выполняет итерацию над чем-то, вы также можете сделать это следующим образом:
root.copy(something.get())
for member in something.get():
# the rest of the loop
Это работает:
for number, member in enumerate(something.get()):
if not number:
root.copy(member)
else:
somewhereElse.copy(member)
foo(member)
В большинстве случаев, однако, я предлагаю просто перебирать что угодно [1:]
и выполнять корневую операцию вне цикла; это обычно более читабельно. Конечно, это зависит от вашего варианта использования.
Я не знаю Python, но я использую почти точный шаблон из вашего примера.
Я также делаю условие if
наиболее частым, поэтому обычно проверяю if (first == false)
Почему? для длинных циклов first будет истинным только один раз и будет ложным все остальные, что означает, что во всех циклах, кроме первого, программа проверит условие и перейдет к части else.
При проверке на ложность первого будет только один переход к другой части. Я действительно не знаю, добавляет ли это вообще эффективности, но я все равно делаю это, просто чтобы быть в мире со своим внутренним ботаником.
PS: Да, я знаю, что при входе в часть if он также должен перепрыгивать через else, чтобы продолжить выполнение, поэтому, вероятно, мой способ сделать это бесполезен, но это приятно. : D
Как насчет использования 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)
Я думаю, что первое решение 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)