これを実行するためのもっと簡単な方法があると確信しています。
リストを返す一連のメソッドを呼び出しています。リストが空の可能性があります。リストが空でない場合は、最初の項目を返します。そうでなければ、Noneを返します。このコードは動作します:
my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None
これを行うには単純な一行の慣用句があるべきだと私には思えますが、私の人生のために私はそれを考えることができません。ある?
編集:
ここで1行の式を探しているのは、信じられないほど簡潔なコードが好きなわけではありませんが、次のようなコードをたくさん書く必要があるからです。
x = get_first_list()
if x:
# do something with x[0]
# inevitably forget the [0] part, and have a bug to fix
y = get_second_list()
if y:
# do something with y[0]
# inevitably forget the [0] part AGAIN, and have another bug to fix
私がやりたいことは確かに関数で達成することができます(そしておそらくそうなるでしょう):
def first_item(list_or_none):
if list_or_none: return list_or_none[0]
x = first_item(get_first_list())
if x:
# do something with x
y = first_item(get_second_list())
if y:
# do something with y
私はこの質問を投稿しました。Pythonの単純な式ができることに私はよく驚いています。そして、単純な式があるならば、関数を書くのは愚かなことだと思いました。しかし、これらの答えを見て、それは関数は簡単な解決策のようです。
next(iter(your_list), None)
your_list
をNone
にすることができる場合:
next(iter(your_list or []), None)
def get_first(iterable, default=None):
if iterable:
for item in iterable:
return item
return default
例:
x = get_first(get_first_list())
if x:
...
y = get_first(get_second_list())
if y:
...
他の選択肢は、上記の関数をインライン化することです。
for x in get_first_list() or []:
# process x
break # process at most one item
for y in get_second_list() or []:
# process y
break
break
を避けるためには、次のように書くことができます。
for x in yield_first(get_first_list()):
x # process x
for y in yield_first(get_second_list()):
y # process y
どこで:
def yield_first(iterable):
for item in iterable or []:
yield item
return
最善の方法はこれです:
a = get_list()
return a[0] if a else None
一行で行うこともできますが、プログラマーにとっては読むのがはるかに困難です。
return (get_list()[:1] or [None])[0]
(get_list() or [None])[0]
それはうまくいくはずです。
ところで、私は変数list
を使用しませんでした。組み込みのlist()
関数を上書きするからです。
編集:私は以前よりも少し単純ですが間違ったバージョンを持っていました。
Listは反復可能なので、Pythonで最も慣用的な方法は、反復子にnext()を使用することです。 2011年12月13日に@ J.F.Sebastianがコメントした内容と同じです。
next(iter(the_list), None)
the_list
が空の場合、Noneを返します。 next()Python 2.6 + を参照してください。
あるいはthe_list
が空でないことを確実に知っているならば:
iter(the_list).next()
を参照--- iterator.next()Python 2.2 +
OPの解決策はもうすぐそこにあります、それをよりPythonicにするためのいくつかのことだけがあります。
一例として、リストの長さを取得する必要はありません。 Pythonの空のリストはifチェックでFalseに評価されます。ただ言うだけ
if list:
さらに、予約語と重複する変数に割り当てるのは非常に悪い考えです。 "list"はPythonの予約語です。
それではそれをに変更しましょう
some_list = get_list()
if some_list:
ここで多くの解決策を見逃しているという非常に重要な点は、すべてのPython関数/メソッドはデフォルトでNoneを返すということです。以下を試してください。
def does_nothing():
pass
foo = does_nothing()
print foo
関数を早く終了させるためにNoneを返す必要がない限り、明示的にNoneを返す必要はありません。かなり簡潔に言えば、最初のエントリがあればそれを返すだけです。
some_list = get_list()
if some_list:
return list[0]
そして最後に、おそらくこれは暗示されていましたが、明示的にするためには 明示的が暗黙的 よりも優れているため)、他の関数からリストを取得してはいけません。単にパラメータとして渡します。したがって、最終結果は次のようになります。
def get_first_item(some_list):
if some_list:
return list[0]
my_list = get_list()
first_item = get_first_item(my_list)
私が言ったように、OPはほぼそこにありました、そしてほんの少しのタッチはそれにあなたが探しているPythonの味を与えます。
リスト内包表記から最初のもの(またはNone)を摘み取ろうとしているのであれば、ジェネレータに切り替えて次のようにすることができます。
next((x for x in blah if cond), None)
Pro:blahがインデックス化できない場合に機能しますCon:それはなじみのない構文です。ただし、ipythonでハッキングしたりフィルタリングしたりするときに便利です。
for item in get_list():
return item
最初の項目を返すPythonイディオムまたはNone?
最もPython的なアプローチは、最も支持された答えが示したものであり、質問を読んだときに頭に浮かんだ最初のものでした。空の可能性のあるリストが関数に渡される場合の最初の使用方法は次のとおりです。
def get_first(l):
return l[0] if l else None
そして、リストがget_list
関数から返された場合:
l = get_list()
return l[0] if l else None
for
これを行う賢い方法を考え始めたとき、これは私が考えた2番目のものです:
for item in get_list():
return item
これは、get_list
が空のリストを返す場合、関数がここで終了し、暗黙的にNone
を返すことを前提としています。以下の明示的なコードはまったく同じです。
for item in get_list():
return item
return None
if some_list
また、暗黙的なNone
を使用する次のものも提案されました(誤った変数名を修正しました)。これは、発生しない可能性のある反復の代わりに論理チェックを使用するため、上記よりも望ましいでしょう。これにより、何が起こっているかをすぐに理解しやすくなります。しかし、読みやすさと保守性のために書いている場合は、最後に明示的なreturn None
も追加する必要があります。
some_list = get_list()
if some_list:
return some_list[0]
or [None]
および0番目のインデックスを選択これは最もよく投票された答えにもあります:
return (get_list()[:1] or [None])[0]
スライスは不要であり、メモリに追加の1項目リストを作成します。以下の方がパフォーマンスが向上します。説明すると、or
はブールコンテキストの最初の要素がFalse
の場合に2番目の要素を返します。したがって、get_list
が空のリストを返す場合、括弧に含まれる式は 'None'のリストを返します。 0
インデックス:
return (get_list() or [None])[0]
次の例では、最初の項目がブール変数コンテキストのTrue
である場合に2番目の項目を返し、my_listを2回参照するため、3項式(技術的には1ライナーではない)よりも優れています。
my_list = get_list()
return (my_list and my_list[0]) or None
next
次に、組み込みのnext
およびiter
を次のように巧妙に使用します。
return next(iter(get_list()), None)
説明すると、iter
は.next
メソッドを持つイテレータを返します。 (Python 3.の[.__next__
3.)次に、組み込みのnext
がその.next
メソッドを呼び出し、イテレータが使い果たされた場合、指定したデフォルトのNone
を返します。
a if b else c
)および循環以下が提案されましたが、通常、論理は負ではなく正で理解されるため、逆の方が望ましいでしょう。 get_list
が2回呼び出されるため、結果が何らかの方法でメモされていない限り、これはパフォーマンスが低下します。
return None if not get_list() else get_list()[0]
より良い逆:
return get_list()[0] if get_list() else None
さらに良いことに、get_list
が1回だけ呼び出されるようにローカル変数を使用すると、最初に説明した推奨Pythonicソリューションが得られます。
l = get_list()
return l[0] if l else None
慣用句に関しては、nth
と呼ばれる itertoolsレシピ があります。
Itertoolsレシピから:
def nth(iterable, n, default=None):
"Returns the nth item or a default value"
return next(islice(iterable, n, None), default)
ワンライナーが必要な場合は、このレシピを実装したライブラリをインストールすることを検討してください。 more_itertools
:
import more_itertools as mit
mit.nth([3, 2, 1], 0)
# 3
mit.nth([], 0) # default is `None`
# None
more_itertools.first
という最初の項目だけを返す別のツールがあります。
mit.first([3, 2, 1])
# 3
mit.first([], default=None)
# None
これらのitertoolsは、リストだけでなく、あらゆるイテラブルに対して一般的に拡張されます。
率直に言って、私はより良い慣用句があるとは思わない:あなたははっきりしていて簡潔である - 「より良い」ものは必要ない。たぶん、これは本当に好みの問題です、あなたはif len(list) > 0:
をif list:
で変えることができました - 空のリストは常にFalseに評価されます。
これに関連して、Pythonはnot Perlです(駄目なのではありません!)。最もクールなコードを入手する必要はありません。
実際、私がPythonで見た中で最悪のコードもまたとてもクールでした:-)そして完全にメンテナンスできませんでした。
ところで、ここで見た解決策の大部分は、list [0]がFalseと評価されるときには考慮に入れません(たとえば、空の文字列、またはゼロ)。この場合、これらはすべてNoneを返し、正しい要素は返しません。
好奇心から、私は2つの解決策にタイミングをかけました。 forループを時期尚早に終了させるためにreturn文を使用する解決策は、Python 2.5.1がインストールされている私のマシンではもう少しコストがかかります。
import random
import timeit
def index_first_item(some_list):
if some_list:
return some_list[0]
def return_first_item(some_list):
for item in some_list:
return item
empty_lists = []
for i in range(10000):
empty_lists.append([])
assert empty_lists[0] is not empty_lists[1]
full_lists = []
for i in range(10000):
full_lists.append(list([random.random() for i in range(10)]))
mixed_lists = empty_lists[:50000] + full_lists[:50000]
random.shuffle(mixed_lists)
if __== '__main__':
ENV = 'import firstitem'
test_data = ('empty_lists', 'full_lists', 'mixed_lists')
funcs = ('index_first_item', 'return_first_item')
for data in test_data:
print "%s:" % data
for func in funcs:
t = timeit.Timer('firstitem.%s(firstitem.%s)' % (
func, data), ENV)
times = t.repeat()
avg_time = sum(times) / len(times)
print " %s:" % func
for time in times:
print " %f seconds" % time
print " %f seconds avg." % avg_time
これらは私が得たタイミングです:
[。] empty_lists: index_first_item: 0.748353秒 0.741186秒 0.741191秒 0.743543秒平均[ ] return_first_item : 0.785511秒 0.822178秒 0.782846秒 0.796845秒平均[ ] full_list: index_first_item: 0.762618秒 0.788040秒 0.786849秒 0.779169秒平均[ return_first_item: 0.802735秒 0.878706秒 ] 0.808781秒[...] 0.830074秒[平均] [[____]混合インデックス:[[____]] index_first_item:[[____]] 0.791129秒[。 。] 0.759699秒平均 return_first_item: 0.784801秒 0.785146秒 0.840193秒 0.803380秒平均
try:
return a[0]
except IndexError:
return None
何人かの人々はこのようなことをすることを提案しました:
list = get_list()
return list and list[0] or None
これは多くの場合に機能しますが、list [0]が0、False、または空の文字列に等しくない場合にのみ機能します。 list [0]が0、False、または空の文字列の場合、このメソッドは誤ってNoneを返します。
私は自分自身のコードでこのバグを何度も作りました!
これはどう:
(my_list and my_list[0]) or None
注:これはオブジェクトのリストに対してはうまく機能するはずですが、以下のコメントに従った数または文字列のリストの場合には間違った答えを返すかもしれません。
def head(iterable):
try:
return iter(iterable).next()
except StopIteration:
return None
print head(xrange(42, 1000) # 42
print head([]) # None
ところで:私はあなたの一般的なプログラムの流れをこのようなものに作り直すつもりです:
lists = [
["first", "list"],
["second", "list"],
["third", "list"]
]
def do_something(element):
if not element:
return
else:
# do something
pass
for li in lists:
do_something(head(li))
(可能な限り繰り返しを避ける)