360

これを行う簡単な方法があると確信していますが、それは私には思い浮かびません。

リストを返す一連のメソッドを呼び出しています。リストが空である可能性があります。リストが空でない場合は、最初の項目を返します。それ以外の場合は、None を返します。このコードは機能します:

my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None

これを行うための簡単な 1 行のイディオムがあるべきだと私には思えますが、私の人生ではそれを思いつきません。ある?

編集:

ここで 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 の単純な式でできることによく驚かされるので、質問を投稿しました。また、単純な式でうまくいく場合、関数を書くのはばかげていると思いました。しかし、これらの答えを見ると、関数が簡単な解決策のように思えます。

4

24 に答える 24

286

Python 2.6+

next(iter(your_list), None)

可能であれば:your_list_None

next(iter(your_list or []), None)

Python 2.4

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
于 2008-12-13T23:31:55.753 に答える
251

最良の方法はこれです:

a = get_list()
return a[0] if a else None

1行でそれを行うこともできますが、プログラマーが読むのははるかに困難です。

return (get_list()[:1] or [None])[0]
于 2008-12-12T20:12:27.513 に答える
88
(get_list() or [None])[0]

それはうまくいくはずです。

listところで、組み込み関数を上書きするため、変数は使用しませんでしたlist()

編集:以前は少し単純ですが、間違ったバージョンがありました。

于 2008-12-12T20:00:03.920 に答える
13

リスト内包表記から最初のもの (または None) を取り出そうとしていることに気付いた場合は、次のようにジェネレーターに切り替えることができます。

next((x for x in blah if cond), None)

長所: 何とかインデックス可能でない場合に機能します。短所: なじみのない構文です。ただし、ipython で何かをハッキングしたりフィルタリングしたりするときに便利です。

于 2016-02-29T14:43:44.513 に答える
11

OPのソリューションはほぼそこにあり、よりPythonicにするためのいくつかのことがあります。

1つは、リストの長さを取得する必要はありません。Pythonの空のリストは、ifチェックでFalseと評価されます。単に言うだけ

if 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フレーバーが得られます。

于 2008-12-12T22:41:48.133 に答える
7

最初のアイテムまたはNoneを返すPythonイディオム?

最もPython的なアプローチは、最も支持された回答が示したものであり、質問を読んだときに最初に頭に浮かんだことでした. 最初に空のリストが関数に渡された場合の使用方法は次のとおりです。

def get_first(l): 
    return l[0] if l else None

リストがget_list関数から返された場合:

l = get_list()
return l[0] if l else None

Python 3.8 の新機能、代入式

代入式は、インプレース代入演算子 (非公式に wallus 演算子と呼ばれます) を:=使用します。これは Python 3.8 で新しく導入されたもので、チェックと代入をインプレースで行うことができ、ワンライナーが可能になります。

return l[0] if (l := get_list()) else None

長年の Python ユーザーとして、これは 1 つの行で多くのことをしようとしているように感じます。パフォーマンスが同等であると推定される方がより良いスタイルだと思います。

if l := get_list():
    return l[0]
return None

この定式化を支持するのは、言語へのこの変更を提案する PEPの Tim Peter のエッセイです。彼は最初の定式化については言及しませんでしたが、彼が気に入った他の定式化に基づいて、彼は気にしないと思います.

ここでこれを行うために実証された他の方法と説明

for

これを行うための賢い方法を考え始めたとき、これが私が考えた2番目のことです:

for item in get_list():
    return item

これは、関数がここで終了すると仮定し、空のリストを返すNone場合は暗黙的に返します。get_list以下の明示的なコードはまったく同等です。

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]してゼロ番目のインデックスを選択

これは、最も投票された回答にもあります。

return (get_list()[:1] or [None])[0]

スライスは不要で、メモリ内に追加の 1 項目リストを作成します。以下は、よりパフォーマンスが向上するはずです。説明すると、最初の要素がブール コンテキストにあるor場合は 2 番目の要素を返すため、空のリストを返す場合、括弧に含まれる式は「なし」のリストを返し、インデックスによってアクセスされます。Falseget_list0

return (get_list() or [None])[0]

次のものは、最初の項目がブール コンテキストにある場合に 2 番目の項目を返すという事実を使用しますTrue。これは my_list を 2 回参照するため、三項式よりも優れているわけではありません (技術的にはワンライナーではありません)。

my_list = get_list() 
return (my_list and my_list[0]) or None

next

次に、ビルトインnextiter

return next(iter(get_list()), None)

説明するために、メソッドiterを持つイテレータを返します。.next( .__next__Python 3.) 次に、ビルトインnextがそのメソッドを呼び出し.next、イテレータが使い果たされた場合、与えられたデフォルトの を返しますNone

冗長な三項式 ( a if b else c) と折り返し

以下が提案されましたが、論理は通常、否定的ではなく肯定的に理解されるため、逆の方が望ましいでしょう。は 2 回呼び出されるためget_list、結果が何らかの方法でメモ化されない限り、パフォーマンスが低下します。

return None if not get_list() else get_list()[0]

より良い逆:

return get_list()[0] if get_list() else None

さらに良いことに、ローカル変数を使用してget_list一度だけ呼び出されるようにすると、最初に説明した推奨される Pythonic ソリューションが得られます。

l = get_list()
return l[0] if l else None
于 2015-07-18T04:33:11.960 に答える
3
for item in get_list():
    return item
于 2008-12-12T21:48:57.867 に答える
2

率直に言って、これ以上のイディオムはないと思います。あなたは明確で簡潔です。「より良い」ものは必要ありません。たぶん、しかしこれは本当に好みの問題です、あなたはで変えることができますif len(list) > 0:-if list:空のリストは常にFalseと評価されます。

関連する注意点として、PythonはPerlではありません(しゃれは意図されていません!)。可能な限りクールなコードを取得する必要はありません。
実際、私がPythonで見た中で最悪のコードも非常にクールで、完全に保守できませんでした:-)。

ちなみに、ここで見たソリューションのほとんどは、list [0]がFalse(たとえば、空の文字列、またはゼロ)と評価されるときに考慮されません。この場合、それらはすべてNoneを返し、正しい要素ではありません。

于 2008-12-12T23:14:19.800 に答える
1

好奇心から、2 つのソリューションでタイミングを計りました。return ステートメントを使用して for ループを途中で終了するソリューションは、Python 2.5.1 を使用している私のマシンでは少しコストがかかります。これは iterable の設定に関係していると思われます。

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 __name__ == '__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

これらは私が得たタイミングです:

空のリスト:
  index_first_item:
    0.748353 秒
    0.741086 秒
    0.741191 秒
    平均 0.743543 秒
  return_first_item:
    0.785511 秒
    0.822178 秒
    0.782846 秒
    平均0.796845秒
フルリスト:
  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.743526 秒
    0.744441 秒
    平均 0.759699 秒
  return_first_item:
    0.784801 秒
    0.785146 秒
    0.840193 秒
    平均0.803380秒
于 2008-12-16T07:07:33.257 に答える
0
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))

(可能な限り繰り返しを避けます)

于 2008-12-16T13:17:12.963 に答える
0

これはどう:

(my_list and my_list[0]) or None

注:これは、オブジェクトのリストに対しては正常に機能するはずですが、以下のコメントに従って、数値または文字列リストの場合は間違った回答を返す可能性があります。

于 2015-06-28T07:57:26.543 に答える
-1
try:
    return a[0]
except IndexError:
    return None
于 2008-12-12T20:30:19.117 に答える
-1

and-orトリックの使用:

a = get_list()
return a and a[0] or None
于 2008-12-12T23:48:00.637 に答える
-1

おそらく最速の解決策ではありませんが、誰もこのオプションについて言及していません:

dict(enumerate(get_list())).get(0)

get_list()返すことができる場合はNone、次を使用できます。

dict(enumerate(get_list() or [])).get(0)

利点:

-一行

get_list()-あなたは一度電話するだけです

- わかりやすい

于 2014-02-04T18:37:07.803 に答える
-2

抽出メソッドを使用できます。つまり、そのコードをメソッドに抽出し、それを呼び出します。

私はそれをもっと圧縮しようとはしません、ワンライナーは冗長バージョンよりも読みにくいようです。そして、Extract Methodを使用する場合、それは1つのライナーです;)

于 2008-12-12T20:10:04.010 に答える
-2

何人かの人々はこのようなことをすることを提案しました:

list = get_list()
return list and list[0] or None

これは多くの場合機能しますが、list [0]が0、False、または空の文字列と等しくない場合にのみ機能します。list [0]が0、False、または空の文字列の場合、メソッドは誤ってNoneを返します。

私は自分のコードでこのバグを何度も作成しました!

于 2008-12-13T00:35:13.630 に答える
-3

Cスタイルの三項演算子に相当する慣用的なpythonではありません

cond and true_expr or false_expr

すなわち。

list = get_list()
return list and list[0] or None
于 2008-12-12T21:55:53.703 に答える