简体   繁体   English

“For”循环第一次迭代

[英]“For” loop first iteration

I would like to inquire if there is an elegant pythonic way of executing some function on the first loop iteration.我想询问是否有一种优雅的 pythonic 方式在第一次循环迭代中执行某些函数。 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)

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.我可以看到不这样做的唯一原因是您将从生成器表达式中获得一个大列表(您不想预先获取它,因为它不适合内存),或类似的情况.

You have several choices for the Head-Tail design pattern.对于Head-Tail设计模式,您有多种选择。

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.人们抱怨这在某种程度上不是“DRY”,因为“冗余 foo(member)”代码。 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?如果你只能有一个引用,那么定义一个函数有什么意义?

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 . 索引方法的文档。

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;不过,在大多数情况下,我建议只迭代 what whatever[1:]并在循环之外做根本的事情; that's usually more readable.这通常更具可读性。 Depends on your use case, of course.当然,这取决于您的用例。

Here, I could come with a Pythonic idiom that can look "pertty".在这里,我可以使用一个看起来“非常”的 Pythonic 习语。 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) (对不起 - 我发布的第一个,在编辑之前,表单不起作用,我忘记了实际获取“复制”对象的迭代器)

I think this is quite elegant, but maybe too convoluted for what it does...我认为这很优雅,但对于它的作用来说可能太复杂了......

from itertools import chain, repeat, izip
for place, member in izip(chain([root], repeat(somewhereElse)), something.get()):
    place.copy(member)
    foo(member)

If something.get() iterates over something, you can do it also as follows:如果 something.get() 迭代某些东西,你也可以这样做:

root.copy(something.get())

for member in something.get():
  #  the rest of the loop

How about using iter , and consuming the first element?使用iter并使用第一个元素怎么样?

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.编辑:回到 OP 的问题上,您要对所有元素执行一个通用操作,然后要对第一个元素执行一个操作,然后对其余元素执行另一个操作。

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)

I think the first S.Lott solution is the best, but there's another choice if you're using a pretty recent python (>= 2.6 I think, since izip_longest doesn't seem available before that version) that lets doing different things for the first element and successive one, and can be easily modified to do distinct operations for 1st, 2nd, 3rd element... as well.我认为第一个 S.Lott 解决方案是最好的,但是如果您使用的是最近的 Python(我认为 >= 2.6,因为 izip_longest 在该版本之前似乎不可用),还有另一种选择,它可以为第一个元素和连续的元素,并且可以很容易地修改为对第一个、第二个、第三个元素进行不同的操作......

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)

Can't you do root.copy(something.get()) before the loop?你不能在循环之前做root.copy(something.get())吗?

EDIT: Sorry, I missed the second bit.编辑:对不起,我错过了第二位。 But you get the general idea.但是你明白了一般的想法。 Otherwise, enumerate and check for 0 ?否则,枚举并检查0 ?

EDIT2: Ok, got rid of the silly second idea. EDIT2:好的,摆脱了愚蠢的第二个想法。

I don't know Python, but I use almost the exact pattern of your example.我不知道 Python,但我几乎使用了您示例中的确切模式。
What I do also is making the if condition the most frequent, so usually check for if( first == false )我所做的也是使if条件最频繁,所以通常检查if( first == false )
Why?为什么? for long loops, first will be true only one time and will be false all the other times, meaning that in all loops but the first, the program will check for the condition and jump to the else part.对于长循环, first 只会有一次为真,其他时候都为假,这意味着在除第一个循环之外的所有循环中,程序将检查条件并跳转到 else 部分。
By checking for first being false, there will be only one jump to the else part.通过检查 first 是否为 false,将只有一次跳转到 else 部分。 I don't really know if this adds efficiency at all, but I do it anyway, just to be in peace with my inner nerd.我真的不知道这是否会增加效率,但我还是这样做了,只是为了与我内心的书呆子和平相处。

PS: Yes, I know that when entering the if part, it also has to jump over the else to continue execution, so probably my way of doing it is useless, but it feels nice. PS:是的,我知道进入if部分的时候,还要跳过else才能继续执行,所以可能我的方法没用,不过感觉不错。 :D :D

Your question is contradictory.你的问题是矛盾的。 You say "only do something on first iteration", when in fact you are saying do something different on first/subsequent iterations.您说“仅在第一次迭代时做某事”,而实际上您是说在第一次/后续迭代中做一些不同的事情。 This is how I would attempt it:这是我尝试的方式:

copyfn = root.copy
for member in something.get():
    copyfn(member)
    foo(member)
    copyfn = somewhereElse.copy

Here is what works for me这对我有用

    dup_count = 0
    for x in reversed(dup_list):
        dup_count += 1
        if dup_count == 1:
            print("First obj {}: {}".format(dup_count,x))
        else:
            print("Object # {}:  {}".format( dup_count,x  ))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM