Question

Je suis sûr qu'il ya un moyen plus simple de faire ce qui est tout simplement pas se produire pour moi.

J'appelle un tas de méthodes qui renvoient une liste. La liste peut être vide. Si la liste est non vide, je veux revenir le premier élément; sinon, je veux revenir Aucun. Ce code fonctionne:

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

Il me semble qu'il devrait être un simple langage d'une ligne pour ce faire, mais pour la vie de moi je ne peux pas y penser. Est-il?

Modifier

La raison pour laquelle je suis à la recherche d'une expression d'une ligne n'est pas que j'aime le code incroyablement laconique, mais parce que je vais avoir à écrire beaucoup de code comme ceci:

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

Ce que je voudrais être faire peut certainement être accompli avec une fonction (et probablement):

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

J'ai posté la question parce que je suis souvent surpris par ce que des expressions simples en Python peut faire, et je pensais que l'écriture d'une fonction était une chose stupide à faire s'il y avait une simple expression pourrait faire l'affaire. Mais en voyant ces réponses, il semble comme une fonction la solution simple.

Était-ce utile?

La solution

Python 2.6 +

next(iter(your_list), None)

Si peut être 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

Exemple:

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

Une autre option est inline la fonction ci-dessus:

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

Pour éviter break vous pouvez écrire:

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

Où:

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

Autres conseils

La meilleure façon est la suivante:

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

Vous pouvez aussi le faire en une seule ligne, mais il est beaucoup plus difficile pour le programmeur à lire:

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

Cela devrait fonctionner.

BTW je n'ai pas utilisé la variable list, parce que la fonction interne écrase la fonction list().

Modifier. J'ai eu une version un peu plus simple, mais ne va pas ici plus tôt

Le plus python façon idiomatiques est d'utiliser la prochaine () sur une iterator puisque la liste est itérables . tout comme ce que @ J.F.Sebastian mettre dans le commentaire le 13 décembre 2011.

next(iter(the_list), None) Ceci retourne None si est vide the_list. voir next () Python 2.6+

ou si vous savez que n'est pas vide iter(the_list).next():

<=> voir iterator.next () Python 2.2+

est presque là la solution de l'OP, il y a juste quelques petites choses pour le rendre plus Pythonic.

D'une part, il n'y a pas besoin d'obtenir la longueur de la liste. listes vides en Python évaluer False dans un si chèque. Il suffit de dire simplement

if list:

En outre, il est une très mauvaise idée d'attribuer à des variables qui se chevauchent avec des mots réservés. « Liste » est un mot réservé en Python.

Alors, nous allons changer cela à

some_list = get_list()
if some_list:

Un point très important que beaucoup de solutions manque ici est que toutes les fonctions Python / méthodes Aucun retour par défaut . Essayez ce qui suit ci-dessous.

def does_nothing():
    pass

foo = does_nothing()
print foo

Sauf si vous devez retourner Aucun mettre fin à une fonction précoce, il est inutile de revenir explicitement Néant. Très succinctement, il suffit de retourner la première entrée, il devrait exister.

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

Et enfin, peut-être cela était sous-entendu, mais juste pour être explicite (parce que explicite mieux que implicite), vous ne devriez pas avoir votre fonction obtenir la liste d'une autre fonction; il suffit de passer en tant que paramètre. Ainsi, le résultat final serait

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

my_list = get_list()
first_item = get_first_item(my_list)

Comme je l'ai dit, l'OP était presque là, et à quelques touches qu'il donne le goût de Python que vous cherchez.

Si vous vous trouvez en essayant de cueillir la première chose (ou aucun) à partir d'une compréhension de la liste, vous pouvez passer à un générateur pour le faire comme:

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

Pro: fonctionne si blah n'est pas indexable Con: il est une syntaxe peu familière. Il est utile alors que le piratage autour et des trucs de filtrage dans ipython bien.

for item in get_list():
    return item

Pour parler franchement, je ne pense pas qu'il y ait un meilleur langage: votre est claire et laconique - pas besoin de quoi que ce soit « meilleur ». Peut-être, mais cela est vraiment une question de goût, vous pouvez changer avec if len(list) > 0: if list: -. Une liste vide sera toujours évaluée à False

Sur une note liée, Python est pas Perl (sans jeu de mots!), Vous n'avez pas d'obtenir le plus cool de code possible.
En fait, le pire code que je l'ai vu en Python, était aussi très cool :-) et complètement ingérable.

Par ailleurs, la plupart de la solution que je l'ai vu ici ne prennent pas en considération lors de la liste [0] évalue False (par exemple une chaîne vide ou zéro) - dans ce cas, ils renvoient tous Aucun et non l'élément correct .

  

langage Python pour revenir premier élément ou pas?

L'approche la plus Pythonic est ce que la réponse la plus upvoted a démontré, et ce fut la première chose à venir à l'esprit quand je lis la question. Voici comment l'utiliser, d'abord si la liste peut être vide est passée dans une fonction:

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

Et si la liste est renvoyée d'une fonction get_list:

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

D'autres moyens ont démontré de le faire ici, avec des explications

for

Quand j'ai commencé à essayer de trouver des moyens intelligents pour ce faire, c'est la deuxième chose que je pensais:

for item in get_list():
    return item

Cela suppose la fonction se termine ici, revenant implicitement si None retourne une liste if some_list vide. Le code ci-dessous explicite est exactement équivalent:

for item in get_list():
    return item
return None

return None

Ce qui suit a été également proposé (je corrige le nom de la variable incorrecte) qui utilise également l'implicite or [None]. Ce serait préférable à ce qui précède, car il utilise la vérification logique au lieu d'une itération qui ne peut pas se produire. Cela devrait être plus facile de comprendre immédiatement ce qui se passe. Mais si nous écrivons pour une meilleure lisibilité et la maintenabilité, nous devons aussi ajouter le explicite à la or fin:

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

et sélectionnez tranche False index zeroth

Celui-ci est aussi dans la réponse la plus haut-voté:

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

La tranche est inutile, et crée une liste d'un élément supplémentaire dans la mémoire. Ce qui suit devrait être plus performant. Pour expliquer, renvoie le deuxième 0 élément si le premier est dans un contexte True booléen, donc si une liste retourne next vide, l'expression contenue dans les parenthèses renvoie une liste avec « Aucun », qui sera ensuite accessible par l'indice de iter:

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

Le prochain utilise le fait que et retourne le deuxième élément si le premier est dans un contexte .next booléen, et comme il fait référence my_list deux fois, il n'y a pas mieux que l'expression ternaire (et techniquement pas un one-liner ):

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

.__next__

Ensuite, nous avons l'utilisation intelligente de la suite et builtin a if b else c <=>

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

Pour expliquer, retourne un itérateur <=> avec une méthode <=>. (En Python 3. <=>), le builtin appelle cette méthode <=> <=>, et si l'itérateur est épuisé, retourne la valeur par défaut que nous donnons, <=>.

expression ternaire redondante (<=>) et encerclant retour

Le ci-dessous a été proposé, mais l'inverse serait préférable, que la logique est généralement mieux comprise dans le positif au lieu du négatif. Depuis est appelé deux fois <=>, à moins que le résultat est memoized d'une certaine façon, ce exécuterait mal:

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

La meilleure inverse:

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

Mieux encore, utiliser une variable locale de sorte que n'est appelé <=> une seule fois, et vous avez la solution recommandée Pythonic d'abord discuté:

<*>

En ce qui concerne les idiomes, il y a une itertools recette appelée nth.

De recettes de itertools:

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

Si vous voulez une seule ligne, pensez à installer une bibliothèque qui implémente cette recette pour vous, par exemple more_itertools:

import more_itertools as mit

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

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

Un autre outil est disponible qui ne retourne le premier élément, appelé more_itertools.first .

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

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

Ces itertools échelle génériquement pour tout itératives, non seulement pour les listes.

Par curiosité, je courais timings sur deux des solutions. La solution qui utilise une instruction de retour à la fin prématurément une boucle est un peu plus cher sur ma machine avec Python 2.5.1, je soupçonne que cela a à voir avec la mise en place itérable.

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

Ce sont les horaires que j'ai obtenu:

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: Je retravaille votre flux de programme général en quelque chose comme ceci:

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

(évitant toute répétition lorsque cela est possible)

Que diriez-vous ceci:

(my_list and my_list[0]) or None

Remarque: Cela devrait fonctionner correctement pour les listes d'objets, mais il pourrait revenir réponse incorrecte en cas de numéro ou liste de chaînes par les commentaires ci-dessous

.

Vous pouvez utiliser Extrait Méthode . En d'autres termes extraire ce code dans une méthode que vous souhaitez ensuite appeler.

Je ne voudrais pas essayer de compresser beaucoup plus, les paquebots semblent un plus difficile à lire que la version bavard. Et si vous utilisez la méthode d'extraction, il est une chemise;)

Utilisation du et ou astuce:

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

Et qu'en est-: next(iter(get_list()), None)? Peut-être pas le plus rapide, mais est standard (à partir de Python 2.6) et succincte.

Probablement pas la solution la plus rapide, mais personne n'a mentionné cette option:

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

si peut revenir get_list() None vous pouvez utiliser:

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

Avantages:

Ligne de -one

simplement appeler -Tu une fois <=>

-Facile à comprendre

Mon cas d'utilisation était que pour établir la valeur d'une variable locale.

Personnellement, je trouve l'essai et à l'exception propre style à lire

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

que découper une liste.

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

       print(mylist[0])

   else:

       print(None)

Plusieurs personnes ont suggéré de faire quelque chose comme ceci:

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

Cela fonctionne dans de nombreux cas, mais il ne fonctionnera que si la liste [0] n'est pas égal à 0, Faux, ou une chaîne vide. Si la liste [0] est 0, Faux, ou une chaîne vide, la méthode retourne de manière incorrecte Aucun.

  
    

Je l'ai créé ce bogue dans mon propre code une fois de trop!

  

est pas le python idiomatiques équivalent aux opérateurs ternaires de type C

cond and true_expr or false_expr
à savoir

.

list = get_list()
return list and list[0] or None
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top