我想询问在第一次循环迭代中是否存在一种优雅的pythonic方式来执行某些功能。我能想到的唯一可能性是:
first = True
for member in something.get():
if first:
root.copy(member)
first = False
else:
somewhereElse.copy(member)
foo(member)
Answers:
头尾设计模式有多种选择。
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 )
人们抱怨这不是“ DRY”,因为“冗余foo(member)”代码。这是一个荒谬的说法。如果是这样,那么所有功能只能使用一次。如果只能有一个引用,定义一个函数有什么意义?
member
。一个member
是头。其他members
在哪里的尾巴。他们都是成员。我不确定你在说什么。
foo
在两个(或多个)位置使用DRY违反了怎么做。该函数已被重用。这不是函数定义的重点吗?
这样的事情应该起作用。
for i, member in enumerate(something.get()):
if i == 0:
# Do thing
# Code for everything
但是,我强烈建议您考虑一下您的代码,看看您是否真的必须这样做,因为它有点“脏”。最好是先获取需要特殊处理的元素,然后对循环中的所有其他元素进行常规处理。
我看不到这样做的唯一原因是要从生成器表达式中获得一个很大的列表(您不希望预先获取它,因为它无法容纳在内存中)或类似情况。
for i, a, b, c, in os.walk(input_dir):
?这给了ValueError: need more than 3 values to unpack
。
python for i,tuple in enumerate(os.walk(...)): a, b, c = tuple
怎么样:
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)
索引方法的文档。
if member is my_array[0]
。但是,如果my_array在索引0和另一个索引处引用相同的对象,这仍然行不通。
这有效:
for number, member in enumerate(something.get()):
if not number:
root.copy(member)
else:
somewhereElse.copy(member)
foo(member)
不过,在大多数情况下,我建议只是迭代whatever[1:]
并在循环外进行根操作。通常更具可读性。当然,这取决于您的用例。
在这里,我可以带一个看起来很“漂亮”的Pythonic习惯用法。虽然,很可能我会使用您在提出问题时建议的形式,只是为了使代码保持更明显,尽管不太优雅。
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'对象获得一个迭代器)
我认为第一个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)
如何使用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)
这对我有用
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 ))
member
这种方式额外污染了名称空间。