Frage

Ich bin sicher, dass es ein einfacherer Weg, dies zu tun, das ist einfach nicht zu mir kommt.

Ich bin ein Bündel von Methoden aufrufen, die eine Liste zurückzukehren. Die Liste kann leer sein. Wenn die Liste nicht leer ist, möchte ich das erste Element zurückzukehren; sonst möchte ich keine zurückzukehren. Dieser Code funktioniert:

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

Es scheint mir, dass es ein einfaches einzeiliges Idiom sein, dies zu tun, sondern für das Leben von mir kann ich nicht daran denken. Gibt es?

Edit:

Der Grund, dass ich mich für einen einzeiligen Ausdruck hier auf der Suche ist nicht, dass ich unglaublich terse Code mag, sondern weil ich habe eine Menge Code wie folgen zu schreiben:

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

Was möchte ich auf jeden Fall mit einer Funktion erreicht werden kann, zu tun (und wahrscheinlich wird):

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

Ich stellt die Frage, weil ich oft überrascht bin, was einfache Ausdrücke in Python tun, und ich dachte, dass eine Funktion zu schreiben eine dumme Sache zu tun war, wenn es ein einfacher Ausdruck ist, konnte den Trick. Aber diese Antworten zu sehen, es scheint wie eine Funktion ist die einfache Lösung.

War es hilfreich?

Lösung

Python 2.6 +

next(iter(your_list), None)

Wenn your_list None werden kann:

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

Beispiel:

x = get_first(get_first_list())
if x:
    ...
y = get_first(get_second_list())
if y:
    ...

Eine weitere Möglichkeit ist die obige Funktion inline:

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

Um zu vermeiden, break Sie schreiben können:

for x in yield_first(get_first_list()):
    x # process x
for y in yield_first(get_second_list()):
    y # process y

Dabei gilt:

def yield_first(iterable):
    for item in iterable or []:
        yield item
        return

Andere Tipps

Der beste Weg ist dies:

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

Sie können es auch tun, in einer Linie, aber es ist viel schwieriger für den Programmierer zu lesen:

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

Das sollte funktionieren.

BTW habe ich nicht den Variable list verwenden, denn das ist die eingebaute list() Funktion überschreibt.

Edit:. Ich hatte eine etwas einfachere, aber falsche Version hier früher

Die meisten Python idiomatische Weg ist es, die nächste () auf einem Iterator zu verwenden, da die Liste ist iterable . wie, was @ J.F.Sebastian in den Kommentar setzen auf 13. Dezember 2011.

next(iter(the_list), None) Dies gibt keine, wenn the_list leer. finden Sie unter next () Python 2.6+

oder wenn Sie sicher the_list wissen nicht leer ist:

iter(the_list).next() finden Sie unter iterator.next () Python 2.2 +

Die Lösung der OP ist fast da, es gibt nur wenige Dinge, die es mehr Pythonic zu machen.

Zum einen gibt es keine Notwendigkeit, die Länge der Liste zu bekommen. Leere Listen in Python zu bewerten auf False in einem if-Check. Einfach nur sagen

if list:

Darüber hinaus ist es eine sehr schlechte Idee, um Variablen zuzuweisen, die mit reservierten Wörtern überlappen. "Liste" ist ein reserviertes Wort in Python.

Also lassen Sie uns das ändern zu

some_list = get_list()
if some_list:

Ein wirklich wichtiger Punkt, dass viele Lösungen hier fehlt, ist, dass alle Python-Funktionen / Methoden Keine Rückkehr von default . Versuchen Sie, die folgenden unten.

def does_nothing():
    pass

foo = does_nothing()
print foo

Wenn Sie keine zurückkehren müssen früh, um eine Funktion zu beenden, ist es nicht erforderlich, keine explizit zurück. Ganz kurz und bündig, nur den ersten Eintrag zurückzukehren, sollte es existieren.

some_list = get_list()
if some_list:
    return list[0]

Und schließlich, vielleicht war dies stillschweigend, aber nur explizit zu sein (weil explizit besser als implizite ), sollten Sie Ihre Funktion aus einer anderen Funktion erhalten Sie die Liste nicht; geben sie nur als Parameter in. So würde das Endergebnis sein

def get_first_item(some_list): 
    if some_list:
        return list[0]

my_list = get_list()
first_item = get_first_item(my_list)

Wie gesagt, war der OP fast da, und nur wenige Berührungen geben ihm die Python Geschmack Sie suchen.

Wenn Sie sich selbst versuchen, das erste, was (oder None) aus einer Liste Verständnis zupfen Sie an einen Generator schalten kann es gerne tun:

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

Pro: funktioniert, wenn blah nicht Wende Con ist: es ungewohnte Syntax ist. Es ist nützlich, während obwohl um und Filter Sachen in ipython Hacking.

for item in get_list():
    return item

Ehrlich gesagt, ich glaube nicht, dass es eine bessere Idiom ist: Sie ist klar und prägnant - keine Notwendigkeit für etwas „besser“. Vielleicht, aber das ist wirklich eine Frage des Geschmacks ist, könnten Sie if len(list) > 0: mit if list: ändern -. Eine leere Liste wird immer auf False auswerten

Auf einem verwandten beachten, Python ist nicht Perl (kein Wortspiel beabsichtigt!), Sie müssen nicht den coolste Code möglich.
Tatsächlich haben die schlechteste Code, den ich in Python zu sehen ist, war auch sehr cool :-) und vollständig wartbaren.

Durch die Art und Weise, die meisten der Lösung, die ich hier gesehen habe nehme nicht in Betracht, wenn die Liste [0] das Ergebnis falsch (zB leere Zeichenkette oder null) - in diesem Fall, sie alles None zurück und nicht das richtige Element .

  

Python Idiom erstes Element oder None zurück?

Die meisten Pythonic Ansatz ist es, was die meisten upvoted Antwort demonstriert, und es war das erste, was mir in den Sinn zu kommen, wenn ich die Frage lesen. Hier ist, wie es zu benutzen, zuerst, wenn die möglicherweise leere Liste in eine Funktion übergeben wird:

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

Und wenn die Liste aus einer get_list Funktion zurückgegeben:

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

Weitere Möglichkeiten demonstriert dies hier zu tun, mit Erklärungen

for

Wenn ich an kluge Weise zu denken begann versuchen, dies zu tun, ist dies das zweite, was ich dachte:

for item in get_list():
    return item

Dies setzt die Funktion hier endet, implizit Rückkehr None wenn get_list eine leere Liste zurückgibt. Der unter expliziter Code entspricht genau:

for item in get_list():
    return item
return None

if some_list

Im Folgenden wurde auch vorgeschlagen (ich die falschen Variablennamen korrigiert), die auch den impliziten None verwendet. Dies würde die obige vorzuziehen sein, da es die logische Überprüfung statt einer Iteration verwendet, die nicht passieren können. Dies sollte einfacher sein, sofort zu verstehen, was geschieht. Aber wenn wir aus Gründen der Lesbarkeit und Wartbarkeit zu schreiben, sollten wir auch den expliziten return None am Ende hinzufügen:

some_list = get_list()
if some_list:
    return some_list[0]

Slice or [None] und wählen nullten Index

Dies ist auch in der meist up-gestimmt Antwort:

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

Die Scheibe ist nicht erforderlich, und schafft eine Extra-Posten-Liste im Speicher. Folgendes sollte mehr performant sein. Um zu erklären, or das zweite Element zurückkehrt, wenn die erste False in einem booleschen Kontext ist, also wenn get_list eine leere Liste zurückgibt, enthielt der Ausdruck in den Klammern eine Liste mit ‚Keine‘ zurück, die dann durch den 0 Index zugegriffen werden :

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

Die nächste nutzt die Tatsache, dass und gibt den zweiten Punkt, wenn die ersten True in einem Booleschen Kontext ist, und da es my_list zweimal verweist, es ist nicht besser als der ternäre Ausdruck (und technisch keinen Einzeiler):

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

next

Dann haben wir die folgende geschickte Nutzung des eingebauten next und iter

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

Um zu erklären, iter gibt einen Iterator mit einem .next Verfahren. (.__next__ in Python 3.) Dann wird die builtin next nennt diese .next Methode, und wenn der Iterator erschöpft ist, gibt den Standard wir geben, None.

redundante ternären Ausdruck (a if b else c) und kreist zurück

Die unten wurde vorgeschlagen, aber die Umkehrung wäre vorzuziehen, wie die Logik in der Regel besser in den positiven anstelle der negativen verstanden wird. Da get_list zweimal aufgerufen wird, es sei denn, das Ergebnis in irgendeiner Weise memoized wird, wäre dies eine schlechte Leistung:

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

Je besser invers:

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

Noch besser ist, eine lokale Variable verwenden, so dass get_list nur einmal aufgerufen wird, und Sie haben die empfohlene Pythonic Lösung zuerst diskutiert:

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

In Bezug auf Idiome gibt es eine itertools Rezept genannt nth.

Von itertools Rezepte:

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)

Wenn Sie Einzeiler wollen, sollten Sie eine Bibliothek installieren, die dieses Rezept für Sie implementiert, z.B. more_itertools :

import more_itertools as mit

mit.nth([3, 2, 1], 0)
# 3

mit.nth([], 0)                                             # default is `None`
# None

Ein weiteres Werkzeug zur Verfügung, das nur das erste Element zurückgibt, die so genannte more_itertools.first .

mit.first([3, 2, 1])
# 3

mit.first([], default=None)
# None

Diese itertools maßstab allgemein für jede iterable, nicht nur für Listen.

Aus Neugier, lief ich Timings auf zwei der Lösungen. Die Lösung, die eine return-Anweisung verwendet eine for-Schleife vorzeitig zu beenden ist etwas teurer auf meinem Rechner mit Python 2.5.1, ich vermuten, dass dies mit dem Einrichten des iterable zu tun hat.

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

Dies sind die Zeiten ich habe:

empty_lists:
  index_first_item:
    0.748353 seconds
    0.741086 seconds
    0.741191 seconds
    0.743543 seconds avg.
  return_first_item:
    0.785511 seconds
    0.822178 seconds
    0.782846 seconds
    0.796845 seconds avg.
full_lists:
  index_first_item:
    0.762618 seconds
    0.788040 seconds
    0.786849 seconds
    0.779169 seconds avg.
  return_first_item:
    0.802735 seconds
    0.878706 seconds
    0.808781 seconds
    0.830074 seconds avg.
mixed_lists:
  index_first_item:
    0.791129 seconds
    0.743526 seconds
    0.744441 seconds
    0.759699 seconds avg.
  return_first_item:
    0.784801 seconds
    0.785146 seconds
    0.840193 seconds
    0.803380 seconds avg.
try:
    return a[0]
except IndexError:
    return None
def head(iterable):
    try:
        return iter(iterable).next()
    except StopIteration:
        return None

print head(xrange(42, 1000)  # 42
print head([])               # None

BTW: Ich würde Ihren allgemeinen Programmablauf in etwa wie folgt überarbeiten:

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))

(Vermeidung von Wiederholungen, wann immer möglich)

Wie wäre es damit:

(my_list and my_list[0]) or None

Hinweis: Dies sollte für Listen von Objekten funktionieren, aber es könnte unter den Kommentaren per falsche Antwort bei Zahlen- oder Zeichenfolgenliste zurück

.

könnten Sie Methode extrahieren . Mit anderen Worten extrahieren, dass Code in eine Methode, die Sie dann nennen würde.

Ich würde nicht versuchen, es zu komprimieren viel mehr, die Einzeiler härter scheinen als die ausführliche Version zu lesen. Und wenn Sie Methode extrahieren verwenden, es ist ein Einzeiler;)

Mit dem und-oder Trick:

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

Und was ist: next(iter(get_list()), None)? Könnte nicht die schnellsten hier sein, aber ist Standard (ab Python 2.6) und prägnant.

Wahrscheinlich nicht die schnellste Lösung, aber niemand erwähnte diese Option:

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

Wenn get_list() kann None zurückkehren können Sie:

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

Vorteile:

-on Zeile

-Sie einfach anrufen get_list() einmal

-einfach verstehen

Mein Anwendungsfall war nur den Wert einer lokalen Variablen zu setzen.

Ich persönlich fand der Versuch und außer Stil sauberer lesen

items = [10, 20]
try: first_item = items[0]
except IndexError: first_item = None
print first_item

als eine Liste schneiden.

items = [10, 20]
first_item = (items[:1] or [None, ])[0]
print first_item
if mylist != []:

       print(mylist[0])

   else:

       print(None)

Einige Leute haben so etwas wie dies vorschlagen tun:

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

Das ist in vielen Fällen funktioniert, aber es funktioniert nur, wenn die Liste [0] nicht gleich 0, False oder eine leere Zeichenfolge. Wenn die Liste [0] 0 ist, False oder eine leere Zeichenfolge, wird die Methode falsch None zurück.

  
    

ich diesen Fehler in meinem eigenen Code erstellt habe einmal zu oft!

  

ist nicht die idiomatische Python entspricht C-Stil ternäre Operatoren

cond and true_expr or false_expr

dh.

list = get_list()
return list and list[0] or None
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top