Tenho certeza de que há uma maneira mais simples de fazer isso que simplesmente não está ocorrendo para mim.
Estou chamando um monte de métodos que retornam uma lista. A lista pode estar vazia. Se a lista não estiver vazia, desejo retornar o primeiro item; caso contrário, desejo retornar Nenhum. Este código funciona:
my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None
Parece-me que deveria haver um idioma de uma linha simples para fazer isso, mas para a minha vida não consigo pensar nisso. Existe?
Editar:
A razão pela qual estou procurando uma expressão de uma linha aqui não é que eu goste de código incrivelmente conciso, mas porque estou tendo que escrever muito código assim:
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
O que eu gostaria de fazer certamente pode ser realizado com uma função (e provavelmente 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
Eu postei a pergunta porque frequentemente fico surpreso com o que expressões simples em Python podem fazer, e achei que escrever uma função era algo tolo de fazer se houvesse uma expressão simples que pudesse resolver o problema. Mas, vendo essas respostas, parece que uma função é a solução simples.
fonte
next(iter(your_list), None)
vez defirst_item(your_list)
assumir queyour_list
não éNone
(get_first_list()
eget_second_list()
sempre deve retornar um iterável).next(iter(your_list))
, se você fornecer um segundo argumentoiter
, estará dizendo que o primeiro argumento é passível de chamada.None
aqui está o segundo parâmetro paranext()
, notiter()
.next()
retorna seu segundo parâmetro se dado em vez de aumentarStopIteration
seyour_list
estiver vazio.Respostas:
Python 2.6 ou superior
Se
your_list
pode serNone
:Python 2.4
Exemplo:
Outra opção é alinhar a função acima:
Para evitar,
break
você pode escrever:Onde:
fonte
""
na lista, ela será descartada e substituída por uma lista vazia[]
. Se você tiver um 0, também será substituído por[]
. Se você tiverFalse
lá, também substituiu. Etc. Você pode se safar disso em um caso específico, mas esse é um mau hábito a ser desenvolvido.bool(lst)
nos diz selen(lst) > 0
não nos diz nada sobre o que os itenslst
contêm,bool([False]) == True;
por exemplo, portanto , a expressão[False] or []
retorna[False]
, o mesmo vale para[0] or []
ela[0]
.yield_first()
para evitarbreak
declarações.A melhor maneira é esta:
Você também pode fazer isso em uma linha, mas é muito mais difícil para o programador ler:
fonte
next(iter(your_list), None)
next(iter(your_list))
é suficienteNone
como o OP pede. Tente:next(iter([]))
.Isso deve funcionar.
BTW eu não usei a variável
list
, porque isso substitui alist()
função interna .Edit: Eu tinha uma versão um pouco mais simples, mas errada aqui anteriormente.
fonte
A maneira mais idiomática do python é usar o next () em um iterador, pois a lista é iterável . exatamente como o @JFSebastian colocou no comentário em 13 de dezembro de 2011.
next(iter(the_list), None)
Isso retorna Nenhum sethe_list
estiver vazio. veja o próximo () Python 2.6+ou se você tiver certeza de que
the_list
não está vazio:iter(the_list).next()
veja iterator.next () Python 2.2 ou superiorfonte
return l[0] if l else None
se a lista fosse um libcomp. Quando a lista é realmente um genexpr isso é ainda melhor desde que você não tem que construir toda a lista como emnext(iter(x for x in range(10) if x % 2 == 0), None)
the_list
não está vazio, você escreveriathe_list[0]
.Se você tentar extrair a primeira coisa (ou Nenhuma) de uma compreensão de lista, poderá mudar para um gerador para fazer o seguinte:
Pro: funciona se blá não é indexável. Con: é uma sintaxe desconhecida. No entanto, é útil enquanto hackers e filtrando coisas no ipython.
fonte
A solução do OP está quase lá, existem apenas algumas coisas para torná-lo mais Pythonic.
Por um lado, não há necessidade de obter o comprimento da lista. Listas vazias no Python são avaliadas como False em uma verificação se. Simplesmente diga
Além disso, é uma péssima idéia atribuir a variáveis que se sobrepõem a palavras reservadas. "lista" é uma palavra reservada em Python.
Então, vamos mudar isso para
Um ponto realmente importante que muitas soluções faltam aqui é que todas as funções / métodos Python retornam None por padrão . Tente o seguinte abaixo.
A menos que você precise retornar None para encerrar uma função mais cedo, é desnecessário retornar explicitamente None. Muito sucintamente, basta retornar a primeira entrada, se ela existir.
E, finalmente, talvez isso esteja implícito, mas apenas para ser explícito (porque explícito é melhor que implícito ), você não deve ter sua função obter a lista de outra função; apenas passe como parâmetro. Então, o resultado final seria
Como eu disse, o OP estava quase lá, e apenas alguns toques proporcionam o sabor Python que você está procurando.
fonte
get_first_item
deve aceitar umdefault
parâmetro (comodict.get
) que seja padronizado como Nenhum. Assim, a interface da função comunica explicitamente o que acontece semy_list
estiver vazio.fonte
Francamente falando, não acho que exista uma linguagem melhor: a sua é clara e concisa - não há necessidade de nada "melhor". Talvez, mas isso é realmente uma questão de gosto, você pode mudar
if len(list) > 0:
comif list:
- uma lista vazia será sempre avaliada como False.Em uma nota relacionada, Python não é Perl (sem trocadilhos!), Você não precisa obter o código mais legal possível.
Na verdade, o pior código que eu já vi em Python, também foi muito legal :-) e completamente insustentável.
A propósito, a maior parte da solução que eu vi aqui não leva em consideração quando a lista [0] é avaliada como False (por exemplo, string vazia ou zero) - nesse caso, todas elas retornam None e não o elemento correto.
fonte
if lst:
vez deif len(lst) > 0:
. Além disso, não use palavras-chave Python como nomes de variáveis; termina em lágrimas. É comum usarL
oulst
como o nome da variável para alguma lista. Tenho certeza de que, neste caso, você não quis sugerir o usolist
como nome de variável, apenas quis dizer "alguma lista". E, +1 para "quando lst [0] for avaliado como Falso".A abordagem mais pitônica é o que a resposta mais votada demonstrou e foi a primeira coisa que me veio à mente quando li a pergunta. Veja como usá-lo, primeiro se a lista possivelmente vazia for passada para uma função:
E se a lista for retornada de uma
get_list
função:Outras maneiras demonstradas para fazer isso aqui, com explicações
for
Quando comecei a tentar pensar em maneiras inteligentes de fazer isso, esta é a segunda coisa que pensei:
Isso pressupõe que a função termine aqui, retornando implicitamente
None
seget_list
retornar uma lista vazia. O código explícito abaixo é exatamente equivalente:if some_list
Também foi proposto o seguinte (eu corrigi o nome incorreto da variável) que também usa o implícito
None
. Isso seria preferível ao acima, pois ele usa a verificação lógica em vez de uma iteração que pode não acontecer. Isso deve ser mais fácil de entender imediatamente o que está acontecendo. Mas se estamos escrevendo para facilitar a leitura e a manutenção, também devemos adicionar o explícitoreturn None
no final:cortar
or [None]
e selecionar o índice zerothEste também está na resposta mais votada:
A fatia é desnecessária e cria uma lista de um item extra na memória. O seguinte deve ter mais desempenho. Para explicar,
or
retorna o segundo elemento se o primeiro estiverFalse
em um contexto booleano; portanto, seget_list
retornar uma lista vazia, a expressão contida entre parênteses retornará uma lista com 'None', que será acessada pelo0
índice:O próximo usa o fato de que e retorna o segundo item se o primeiro estiver
True
em um contexto booleano, e como ele faz referência a my_list duas vezes, não é melhor que a expressão ternária (e tecnicamente não é uma linha):next
Então, temos o seguinte uso inteligente do built-in
next
eiter
Para explicar,
iter
retorna um iterador com um.next
método (.__next__
no Python 3.) Em seguida, o builtinnext
chama esse.next
método e, se o iterador estiver esgotado, retorna o padrão que fornecemosNone
,.expressão ternária redundante (
a if b else c
) e retornandoO abaixo foi proposto, mas o inverso seria preferível, pois a lógica é geralmente melhor compreendida no positivo, em vez do negativo. Como
get_list
é chamado duas vezes, a menos que o resultado seja memorizado de alguma forma, isso teria um desempenho ruim:O melhor inverso:
Melhor ainda, use uma variável local para que isso
get_list
seja chamado apenas uma vez e você tenha a solução Pythonic recomendada discutida primeiro:fonte
Em relação aos idiomas, há uma receita de ferramentas chamada
nth
.De receitas itertools:
Se você quiser one-liners, considere instalar uma biblioteca que implemente esta receita para você, por exemplo
more_itertools
:Está disponível outra ferramenta que retorna apenas o primeiro item, chamado
more_itertools.first
.Esses instrumentos são dimensionados genericamente para qualquer iterável, não apenas para listas.
fonte
my_list[0] if len(my_list) else None
fonte
len
sem motivo. Se você fosse excluí-lo, o código acima faria a mesma coisa.Por curiosidade, corri horários em duas das soluções. A solução que usa uma declaração de retorno para finalizar prematuramente um loop for é um pouco mais cara na minha máquina com o Python 2.5.1. Suspeito que isso tenha a ver com a configuração do iterável.
Estes são os horários que recebi:
fonte
fonte
if len(a) > 0:
mas isso é considerado um bom estilo. Observe como isso expressa o problema: "tente extrair o cabeçalho de uma lista e, se isso não der certo, retorneNone
". Google procurar "EAFP" ou olhar aqui: python.net/~goodger/projects/pycon/2007/idiomatic/...BTW: Eu refiz o fluxo geral do seu programa para algo assim:
(Evitando repetições sempre que possível)
fonte
Que tal agora:
(my_list and my_list[0]) or None
Nota: Isso deve funcionar bem para listas de objetos, mas pode retornar resposta incorreta no caso de número ou lista de cadeias conforme os comentários abaixo.
fonte
([0,1] and 0) or None
!(['','A'] and '') or None
.my_list[0]
for avaliado comoFalse
, o resultado deve serNone
.my_list[0] if len(my_list) else None
Não tenho certeza de quão pythonic é isso, mas até que haja uma primeira função na biblioteca, eu incluo isso na fonte:
É apenas uma linha (está de acordo com o preto) e evita dependências.
fonte
Usando o truque and-or:
fonte
Provavelmente não é a solução mais rápida, mas ninguém mencionou esta opção:
if
get_list()
pode retornarNone
você pode usar:Vantagens:
-uma linha
-você liga
get_list()
uma vez-fácil de entender
fonte
Meu caso de uso foi apenas para definir o valor de uma variável local.
Pessoalmente, achei a tentativa e, exceto o limpador de estilo, para ler
do que fatiar uma lista.
fonte
Várias pessoas sugeriram fazer algo assim:
Isso funciona em muitos casos, mas só funcionará se a lista [0] não for igual a 0, False ou uma sequência vazia. Se a lista [0] for 0, False ou uma sequência vazia, o método retornará incorretamente Nenhum.
fonte
Você pode usar o método Extrair . Em outras palavras, extraia esse código em um método que você chamaria.
Eu não tentaria compactá-lo muito mais, os forros parecem mais difíceis de ler do que a versão detalhada. E se você usar o Extract Method, é um liner;)
fonte
fonte
não é o python idiomático equivalente aos operadores ternários do estilo C
ie
fonte