最初のループの繰り返しでいくつかの関数を実行するエレガントなPythonの方法があるかどうかを問い合わせたいです。私が考えることができる唯一の可能性は次のとおりです。
first = True
for member in something.get():
if first:
root.copy(member)
first = False
else:
somewhereElse.copy(member)
foo(member)
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)」コードのため、これはどういうわけか「DRY」ではないと人々は泣き言を言う。それはばかげた主張です。それが当てはまる場合、すべての関数は一度しか使用できません。参照を1つしか持てない場合、関数を定義する意味は何ですか?
このような何かが動作するはずです。
for i, member in enumerate(something.get()):
if i == 0:
# Do thing
# Code for everything
ただし、コードを考えて、この方法で行う必要があるかどうかを確認することを強くお勧めします。これは、一種の「ダーティー」だからです。前もって特別な処理を必要とする要素を取得し、ループ内の他のすべての処理を定期的に実行する方が良いでしょう。
このようにしないとわかる唯一の理由は、ジェネレータ式から取得する大きなリスト(メモリに収まらないため、前もってフェッチしたくない)、または同様の状況です。
どうですか:
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 のドキュメント。
私はこれは非常にエレガントだと思うが、それが何をするのか複雑すぎるかもしれない...
from itertools import chain, repeat, izip
for place, member in izip(chain([root], repeat(somewhereElse)), something.get()):
place.copy(member)
foo(member)
ここでは、 "pertty"に見えるPythonのイディオムを使用できます。おそらく、質問をするときにあなたが提案したフォームを使用するでしょうが、エレガントではありませんが、コードがより明確に残るようにするためです。
def copy_iter():
yield root.copy
while True:
yield somewhereElse.copy
for member, copy in Zip(something.get(), copy_iter()):
copy(member)
foo(member)
(申し訳ありません-編集する前に最初に投稿したフォームは機能しませんでした。実際に「コピー」オブジェクトのイテレータを取得するのを忘れていました)
これは動作します:
for number, member in enumerate(something.get()):
if not number:
root.copy(member)
else:
somewhereElse.copy(member)
foo(member)
ただし、ほとんどの場合、whatever[1:]
を繰り返し処理し、ループの外側でルート処理を行うことをお勧めします。それは通常より読みやすいです。もちろん、ユースケースに依存します。
最初のS.Lottソリューションが最善だと思いますが、かなり最近のpython(> = 2.6バージョン)これにより、最初の要素と連続する要素に対して異なる処理を実行できます。また、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)
iter
を使用して、最初の要素を消費するのはどうですか?
編集: OPの質問に戻ると、すべての要素に対して実行する共通操作があり、最初の要素に対して実行する操作と、残りの要素に対して実行する操作があります。
単一の関数呼び出しである場合は、2回だけ記述します。それは世界を終わらせません。より複雑な場合は、デコレータを使用して、「最初の」関数と「残りの」関数を共通の操作でラップできます。
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)
Something.get()が何かを反復処理する場合は、次の方法でも実行できます。
root.copy(something.get())
for member in something.get():
# the rest of the loop
私はPythonを知りませんが、あなたの例のほとんど正確なパターンを使用します。
私がやることは、if
条件を最も頻繁にすることなので、通常はif( first == false )
をチェックします
なぜ?長いループの場合、firstは1回だけtrueになり、他のすべての時間にfalseになります。つまり、最初のループを除くすべてのループで、プログラムは条件をチェックしてelse部分にジャンプします。
最初にfalseであるかどうかをチェックすることにより、else部分へのジャンプは1つだけになります。これで効率が上がるかどうかはわかりませんが、とにかく、内なるオタクと安心するためにそれを行います。
PS:はい、if部分に入ると、実行を継続するためにelseを飛び越えなければならないことを知っているので、おそらくそれを行う方法は役に立たないでしょうが、いい感じです。 :D
ループの前にroot.copy(something.get())
できませんか?
編集:申し訳ありませんが、2番目のビットを見逃しました。しかし、あなたは一般的なアイデアを得る。それ以外の場合は、0
を列挙して確認しますか?
EDIT2:わかりました、愚かな2番目のアイデアを取り除きました。
あなたの質問は矛盾しています。実際には、最初/後続のイテレーションで何か別のことを行うと言っているのに、「最初のイテレーションでのみ何かをする」と言います。これは私がそれを試みる方法です:
copyfn = root.copy
for member in something.get():
copyfn(member)
foo(member)
copyfn = somewhereElse.copy