“For” loop first iteration

2019-01-16 17:53发布

Greetings pyc-sires and py-ladies, I would like to inquire if there is an elegant pythonic way of executing some function on the first loop iteration. The only possibility I can think of is:

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

12条回答
淡お忘
2楼-- · 2019-01-16 18:09

You have several choices for the Head-Tail design pattern.

seq= something.get()
root.copy( seq[0] )
foo( seq[0] )
for member in seq[1:]:
    somewhereElse.copy(member)
    foo( member )

Or this

seq_iter= iter( something.get() )
head = seq_iter.next()
root.copy( head )
foo( head )
for member in seq_iter:
    somewhereElse.copy( member )
    foo( member )

People whine that this is somehow not "DRY" because the "redundant foo(member)" code. That's a ridiculous claim. If that was true then all functions could only be used once. What's the point of defining a function if you can only have one reference?

查看更多
Evening l夕情丶
3楼-- · 2019-01-16 18:15

Here, I could come with a Pythonic idiom that can look "pertty". Although, most likely I'd use the form you suggested in asking the question, just for the code to remain more obvious, though less elegant.

def copy_iter():
    yield root.copy
    while True:
        yield somewhereElse.copy

for member, copy in zip(something.get(), copy_iter()):
    copy(member)
    foo(member)

(sorry - the first I posted, before editing, form would not work, I had forgotten to actually get an iterator for the 'copy' object)

查看更多
对你真心纯属浪费
4楼-- · 2019-01-16 18:19

This works:

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

In most cases, though, I'd suggest just iterating over whatever[1:] and doing the root thing outside the loop; that's usually more readable. Depends on your use case, of course.

查看更多
Root(大扎)
5楼-- · 2019-01-16 18:20

Something like this should work.

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

However, I would strongly recommend thinking about your code to see if you really have to do it this way, because it's sort of "dirty". Better would be to fetch the element that needs special handling up front, then do regular handling for all the others in the loop.

The only reason I could see for not doing it this way is for a big list you'd be getting from a generator expression (which you wouldn't want to fetch up front because it wouldn't fit in memory), or similar situations.

查看更多
甜甜的少女心
6楼-- · 2019-01-16 18:20

How about using iter, and consuming the first element?

Edit: Going back on the OP's question, there is a common operation that you want to perform on all elements, and then one operation you want to perform on the first element, and another on the rest.

If it's just a single function call, I'd say just write it twice. It won't end the world. If it's more involved, you can use a decorator to wrap your "first" function and "rest" function with a common operation.

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)

Output:

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

or you could do a slice:

first(items[0])
for item in items[1:]:
    rest(item)
查看更多
虎瘦雄心在
7楼-- · 2019-01-16 18:22

how about:

my_array = something.get()
for member in my_array:
    if my_array.index(member) == 0:
        root.copy(member)
    else:
        somewhereElse.copy(member)
    foo(member)

or maybe:

for index, member in enumerate(something.get()):
    if index == 0:
        root.copy(member)
    else:
        somewhereElse.copy(member)
    foo(member)

Documentation of index-method.

查看更多
登录 后发表回答