Estoy seguro de que hay una manera más simple de hacer esto que simplemente no se me ocurre.
Estoy llamando a un montón de métodos que devuelven una lista. La lista puede estar vacía. Si la lista no está vacía, quiero devolver el primer elemento; de lo contrario, quiero devolver ninguno. Este código funciona:
my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None
Me parece que debería haber un lenguaje simple de una línea para hacer esto, pero por mi vida no puedo pensar en eso. ¿Esta ahí?
Editar:
La razón por la que estoy buscando una expresión de una línea aquí no es que me guste el código increíblemente conciso, sino porque tengo que escribir mucho código como este:
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
Lo que me gustaría hacer sin duda se puede lograr con una función (y probablemente lo será):
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
Publiqué la pregunta porque con frecuencia me sorprende lo que pueden hacer las expresiones simples en Python, y pensé que escribir una función era algo tonto si había una expresión simple que pudiera hacer el truco. Pero al ver estas respuestas, parece que una función es la solución simple.
fuente
next(iter(your_list), None)
lugar defirst_item(your_list)
asumiryour_list
que no lo esNone
(get_first_list()
yget_second_list()
siempre debe devolver un iterable).next(iter(your_list))
, ya que si proporciona un segundo argumento paraiter
, le está diciendo que el primer argumento es invocable.None
aquí está el segundo parámetro paranext()
, noiter()
.next()
devuelve su segundo parámetro si se proporciona en lugar de aumentarStopIteration
siyour_list
está vacío.Respuestas:
Python 2.6+
Si
your_list
puede serNone
:Python 2.4
Ejemplo:
Otra opción es alinear la función anterior:
Para evitar que
break
puedas escribir:Dónde:
fuente
""
en la lista, se descarta y se reemplaza por una lista vacía[]
. Si tienes un 0, también reemplazado por[]
. Si tienesFalse
allí, también reemplazado. Etc. Puede salirse con la suya en un caso específico, pero este es un mal hábito para desarrollar.bool(lst)
nos dice silen(lst) > 0
no nos dice nada sobre qué elementoslst
contiene,bool([False]) == True;
por ejemplo, por lo tanto , la expresión[False] or []
regresa[False]
, lo mismo es para[0] or []
que regrese[0]
.yield_first()
para evitar labreak
declaración.La mejor manera es esta:
También puede hacerlo en una línea, pero es mucho más difícil de leer para el programador:
fuente
next(iter(your_list), None)
next(iter(your_list))
es suficienteNone
como OP pregunta. Proveedores:next(iter([]))
.Eso debería funcionar.
Por cierto, no utilicé la variable
list
, porque eso sobrescribe lalist()
función incorporada .Editar: tuve una versión un poco más simple, pero incorrecta aquí anteriormente.
fuente
La forma más idiomática de Python es usar next () en un iterador ya que la lista es iterable . justo como lo que @JFSebastian puso en el comentario el 13 de diciembre de 2011.
next(iter(the_list), None)
Esto devuelve Ninguno sithe_list
está vacío. ver siguiente () Python 2.6+o si sabes con certeza
the_list
que no está vacío:iter(the_list).next()
ver iterator.next () Python 2.2+fuente
return l[0] if l else None
si la lista fuera libcomp. Cuando la lista es en realidad un genexpr esto es aún mejor, ya que no tiene que construir toda la lista como ennext(iter(x for x in range(10) if x % 2 == 0), None)
the_list
que no está vacío, escribiríathe_list[0]
.Si te encuentras tratando de extraer lo primero (o Ninguno) de una lista de comprensión, puedes cambiar a un generador para hacerlo como:
Pro: funciona si bla no es indexable Con: es una sintaxis desconocida. Sin embargo, es útil al piratear y filtrar cosas en ipython.
fuente
La solución del OP está casi allí, solo hay algunas cosas para hacerlo más Pythonic.
Por un lado, no es necesario obtener la longitud de la lista. Las listas vacías en Python evalúan a False en una comprobación if. Solo di
Además, es una muy mala idea asignar variables que se superponen con palabras reservadas. "lista" es una palabra reservada en Python.
Así que cambiemos eso a
Un punto realmente importante que muchas de las soluciones aquí pasan por alto es que todas las funciones / métodos de Python no devuelven ninguno de forma predeterminada . Pruebe lo siguiente a continuación.
A menos que necesite devolver None para terminar una función antes, no es necesario devolver None explícitamente. Muy sucintamente, solo devuelva la primera entrada, en caso de que exista.
Y finalmente, tal vez esto estaba implícito, pero solo para ser explícito (porque explícito es mejor que implícito ), no debería hacer que su función obtenga la lista de otra función; solo pásalo como parámetro. Entonces, el resultado final sería
Como dije, el OP estaba casi allí, y solo unos pocos toques le dan el sabor Python que estás buscando.
fuente
get_first_item
debería aceptar undefault
parámetro (comodict.get
) que por defecto sea Ninguno. Por lo tanto, la interfaz de la función comunica explícitamente lo que sucede simy_list
está vacío.fuente
Hablando francamente, no creo que haya una mejor expresión idiomática: la tuya es clara y concisa, no hay necesidad de nada "mejor". Tal vez, pero esto es realmente una cuestión de gusto, usted podría cambiar
if len(list) > 0:
conif list:
- una lista vacía siempre evaluará a falso.En una nota relacionada, Python no es Perl (¡sin juego de palabras!), No tiene que obtener el código más genial posible.
En realidad, el peor código que he visto en Python, también fue genial :-) y completamente imposible de mantener.
Por cierto, la mayor parte de la solución que he visto aquí no tiene en cuenta cuando la lista [0] se evalúa como False (por ejemplo, cadena vacía o cero); en este caso, todos devuelven None y no el elemento correcto.
fuente
if lst:
lugar de hacerloif len(lst) > 0:
. Además, no use palabras clave de Python como nombres de variables; termina en lágrimas. Es común usarL
olst
como nombre de variable para alguna lista. Estoy seguro de que en este caso no quiso sugerir que se usara realmentelist
como un nombre de variable, solo quiso decir "alguna lista". Y, +1 para "cuando lst [0] se evalúa como False".El enfoque más pitónico es lo que demostró la respuesta más votada, y fue lo primero que se me ocurrió cuando leí la pregunta. Aquí se explica cómo usarlo, primero si la lista posiblemente vacía se pasa a una función:
Y si la lista se devuelve desde una
get_list
función:Otras formas demostradas para hacer esto aquí, con explicaciones
for
Cuando comencé a pensar en formas inteligentes de hacer esto, esta es la segunda cosa que pensé:
Esto supone que la función termina aquí, devolviendo implícitamente
None
siget_list
devuelve una lista vacía. El siguiente código explícito es exactamente equivalente:if some_list
También se propuso lo siguiente (corrigí el nombre de variable incorrecto) que también usa lo implícito
None
. Esto sería preferible a lo anterior, ya que utiliza la verificación lógica en lugar de una iteración que puede no ocurrir. Esto debería ser más fácil de entender de inmediato lo que está sucediendo. Pero si estamos escribiendo para facilitar la lectura y el mantenimiento, también deberíamos agregar el explícitoreturn None
al final:cortar
or [None]
y seleccionar el índice ceroEsta también está en la respuesta más votada:
El segmento no es necesario y crea una lista adicional de un elemento en la memoria. Lo siguiente debería ser más eficiente. Para explicar,
or
devuelve el segundo elemento si el primero estáFalse
en un contexto booleano, por lo que siget_list
devuelve una lista vacía, la expresión contenida entre paréntesis devolverá una lista con 'Ninguno', a la que luego accederá el0
índice:El siguiente usa el hecho de que devuelve el segundo elemento si el primero está
True
en un contexto booleano, y dado que hace referencia a my_list dos veces, no es mejor que la expresión ternaria (y técnicamente no es una línea):next
Luego tenemos el siguiente uso inteligente del builtin
next
yiter
Para explicar,
iter
devuelve un iterador con un.next
método. (.__next__
En Python 3.) A continuación, la orden internanext
llamadas que.next
el método, y si el iterador está agotado, devuelve el valor por defecto que damos,None
.expresión ternaria redundante (
a if b else c
) y vuelta en círculoSe propuso lo siguiente, pero sería preferible lo inverso, ya que la lógica generalmente se entiende mejor en lo positivo que en lo negativo. Como
get_list
se llama dos veces, a menos que el resultado se memorice de alguna manera, esto funcionaría mal:El mejor inverso:
Aún mejor, use una variable local para que
get_list
solo se llame una vez, y primero tendrá la solución Pythonic recomendada:fuente
En cuanto a los modismos, hay una receta itertools llamada
nth
.De las recetas de itertools:
Si desea frases sencillas, considere instalar una biblioteca que implemente esta receta para usted, por ejemplo
more_itertools
:Hay otra herramienta disponible que solo devuelve el primer elemento, llamado
more_itertools.first
.Estas herramientas de iteración escalan genéricamente para cualquier iterable, no solo para listas.
fuente
my_list[0] if len(my_list) else None
fuente
len
sin ninguna razón. Si fuera a eliminarlo, el código anterior haría lo mismo.Por curiosidad, corrí tiempos en dos de las soluciones. La solución que utiliza una declaración de devolución para finalizar prematuramente un bucle for es un poco más costosa en mi máquina con Python 2.5.1, sospecho que esto tiene que ver con la configuración del iterable.
Estos son los horarios que obtuve:
fuente
fuente
if len(a) > 0:
pero esto se considera un buen estilo. Tenga en cuenta lo bien que esto expresa el problema: "intente extraer el encabezado de una lista, y si eso no funciona, vuelvaNone
". Busque en Google "EAFP" o busque aquí: python.net/~goodger/projects/pycon/2007/idiomatic/…Por cierto: retrabajaría el flujo general de su programa en algo como esto:
(Evitar la repetición siempre que sea posible)
fuente
Qué tal esto:
(my_list and my_list[0]) or None
Nota: Esto debería funcionar bien para las listas de objetos, pero podría devolver una respuesta incorrecta en caso de una lista de números o cadenas según los comentarios a continuación.
fuente
([0,1] and 0) or None
!(['','A'] and '') or None
.my_list[0]
se evalúa comoFalse
, el resultado debería serNone
.my_list[0] if len(my_list) else None
No estoy seguro de cuán pitónico es esto, pero hasta que haya una primera función en la biblioteca, incluyo esto en la fuente:
Es solo una línea (se ajusta al negro) y evita dependencias.
fuente
Usando el truco o:
fuente
Probablemente no sea la solución más rápida, pero nadie mencionó esta opción:
si
get_list()
puede regresarNone
puede usar:Ventajas:
-una línea
-solo llamas
get_list()
una vez-fácil de comprender
fuente
Mi caso de uso fue solo para establecer el valor de una variable local.
Personalmente encontré la prueba y excepto el limpiador de estilo para leer
que cortar una lista.
fuente
Varias personas han sugerido hacer algo como esto:
Eso funciona en muchos casos, pero solo funcionará si la lista [0] no es igual a 0, Falso o una cadena vacía. Si list [0] es 0, False o una cadena vacía, el método devolverá None de forma incorrecta.
fuente
Puedes usar el método de extracción . En otras palabras, extraiga ese código en un método que luego llamaría.
No trataría de comprimirlo mucho más, los revestimientos parecen más difíciles de leer que la versión detallada. Y si usa el método de extracción, es un trazador de líneas;)
fuente
fuente
no es la pitón idiomática equivalente a operadores ternarios de estilo C
es decir.
fuente