Цикл "For" первая итерация - PullRequest
       21

Цикл "For" первая итерация

60 голосов
/ 18 декабря 2009

Я хотел бы узнать, существует ли элегантный питонический способ выполнения какой-либо функции на первой итерации цикла. Единственная возможность, о которой я могу думать, это:

first = True
for member in something.get():
    if first:
        root.copy(member)
        first = False
    else:
        somewhereElse.copy(member)
    foo(member)

Ответы [ 12 ]

60 голосов
/ 18 декабря 2009

Как-то так должно работать.

for i, member in enumerate(something.get()):
    if i == 0:
         # Do thing
    # Code for everything

Тем не менее, я настоятельно рекомендую подумать о вашем коде, чтобы увидеть, действительно ли вы должны делать это таким образом, потому что он вроде «грязный». Лучше было бы выбрать элемент, который требует специальной обработки, а затем выполнить регулярную обработку для всех остальных в цикле.

Единственная причина, по которой я не смог сделать это, - большой список, который вы получите из выражения генератора (который вы не захотите извлекать заранее, потому что он не помещается в памяти), или аналогичные ситуации.

36 голосов
/ 18 декабря 2009

У вас есть несколько вариантов дизайна 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)" Это нелепое утверждение. Если это так, то все функции можно использовать только один раз. Какой смысл определять функцию, если вы можете иметь только одну ссылку?

11 голосов
/ 20 декабря 2009

как насчет:

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)

Документация индекс-метод .

6 голосов
/ 18 декабря 2009

Я думаю, что это довольно элегантно, но, возможно, слишком запутанно для того, что делает ...

from itertools import chain, repeat, izip
for place, member in izip(chain([root], repeat(somewhereElse)), something.get()):
    place.copy(member)
    foo(member)
5 голосов
/ 18 декабря 2009

Здесь я мог бы прийти с 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)

(извините - при первом опубликовании до редактирования форма работать не будет, я забыл получить итератор для объекта 'copy')

4 голосов
/ 18 декабря 2009

Это работает:

for number, member in enumerate(something.get()):
    if not number:
        root.copy(member)
    else:
        somewhereElse.copy(member)
    foo(member)

Тем не менее, в большинстве случаев я бы рекомендовал просто выполнить итерацию по whatever[1:] и выполнить корневую операцию вне цикла; это обычно более читабельно. Конечно, зависит от вашего варианта использования.

3 голосов
/ 18 декабря 2009

Я думаю, что первое решение 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)
3 голосов
/ 18 декабря 2009

Как насчет использования iter и потребления первого элемента?

Редактировать: Возвращаясь к вопросу ОП, есть общая операция, которую вы хотите выполнить со всеми элементами, а затем одна операция, которую вы хотите выполнить с первым элементом, а другая - с остальными. .

Если это всего лишь один вызов функции, я бы сказал, что просто напишите это дважды. Это не конец миру. Если это более сложно, вы можете использовать декоратор, чтобы обернуть вашу «первую» функцию и функцию «отдых» обычной операцией.

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)
3 голосов
/ 18 декабря 2009

Если что-то .get () перебирает что-то, вы можете сделать это также следующим образом:

root.copy(something.get())

for member in something.get():
  #  the rest of the loop
1 голос
/ 18 декабря 2009

Я не знаю Python, но я использую почти точную схему вашего примера.
Я также делаю условие if наиболее частым, поэтому обычно проверяйте на if( first == false )
Зачем? для длинных циклов first будет истинным только один раз и будет ложным все остальное время, что означает, что во всех циклах, кроме первого, программа проверит условие и перейдет к другой части.
Если вы проверили, что сначала ложь, будет только один переход к остальной части. Я действительно не знаю, добавляет ли это вообще эффективности, но я все равно делаю это, просто чтобы быть в мире со своим внутренним ботаником.

PS: Да, я знаю, что при входе в часть if он также должен перепрыгнуть через остальное, чтобы продолжить выполнение, поэтому, вероятно, мой способ сделать это бесполезен, но это приятно. : D

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...