Teste se uma variável é uma lista ou tupla

234

Em python, qual é a melhor maneira de testar se uma variável contém uma lista ou uma tupla? (ou seja, uma coleção)

É isinstance()tão mau como sugerido aqui? http://www.canonical.org/~kragen/isinstance/

Atualização: a razão mais comum pela qual desejo distinguir uma lista de uma string é quando tenho uma estrutura de árvore / dados aninhada indefinidamente profunda de listas de listas de listas de strings etc. que estou explorando com um algoritmo recursivo e preciso para saber quando atingi os nós da "folha".

interstar
fonte
72
Descartar amplamente a verificação de tipo como má é um pouco fácil. Faz parte do idioma. Se é tão mau, alguém deve escrever um PEP para removê-lo.
Adam Crossland
4
@ Adam Crossland: "Faz parte do idioma". Assim como a divisão por zero. É evitável. Nesse caso, sem informações adicionais, provavelmente é completamente desnecessário. A maioria das verificações de tipo no Python é desnecessária. Como nem tudo é desnecessário, algumas verificações de tipo precisam estar presentes. Mas isso não significa que seja útil, valioso ou até uma boa ideia.
S.Lott 2/02
11
Então, você está dizendo que é necessária alguma verificação de tipo, mas, apesar disso, é inútil, inútil e uma má idéia. Desculpe, isso simplesmente não faz sentido.
Glenn Maynard
18
O "XXX é mau" é uma abreviação mal concebida e enganosa para "a maneira como você está pedindo para fazer XXX sugere que você não entende quando ele realmente deve ser usado e você quase certamente quer outra coisa". Provavelmente é o caso aqui.
Glenn Maynard
2
Eu não o descartei amplamente como mau. Escrevi um pequeno ensaio sobre quando é mau e quando é justificável. Esse ensaio pode ser muitas coisas - certo, errado, claro, vago, agradável, chato -, mas uma coisa que não é é uma ampla rejeição da técnica.
Kragen Javier Sitaker,

Respostas:

101

Vá em frente e use isinstancese precisar. É um tanto ruim, pois exclui sequências personalizadas, iteradores e outras coisas que você realmente pode precisar. No entanto, às vezes você precisa se comportar de maneira diferente se alguém, por exemplo, passa uma string. Minha preferência seria verificar explicitamente strou algo unicodeassim:

import types
isinstance(var, types.StringTypes)

NB Não confunda types.StringTypecom types.StringTypes. Este último incorpora stre unicodeobjeta.

O typesmódulo é considerado por muitos obsoleto em favor de apenas verificar diretamente o tipo de objeto; portanto, se você preferir não usar o acima, pode alternativamente verificar explicitamente contra stre unicode, assim:

isinstance(var, (str, unicode)):

Editar:

Melhor ainda é:

isinstance(var, basestring)

Finalizar edição

Depois de qualquer uma dessas opções, você pode voltar a se comportar como se estivesse obtendo uma sequência normal, permitindo que as não-sequências gerem exceções apropriadas.

Ver o que é "mau" na verificação de tipos não é que você queira se comportar de maneira diferente para um determinado tipo de objeto, é que você restringe artificialmente sua função de fazer a coisa certa com tipos de objetos inesperados que, de outra forma, fariam a coisa certa. Se você tiver um fallback final que não é verificado por tipo, remova essa restrição. Deve-se observar que muita verificação de tipo é um cheiro de código que indica que você pode querer refatorar, mas isso não significa necessariamente que você deve evitá-la do getgo.

jcdyer
fonte
2
O módulo types é um artefato histórico. Como mencionado em docs.python.org/dev/library/types.html#module-types, se você realmente precisa verificar o strtipo, basta usá-lo diretamente, em vez de usar types.StringTypequal é apenas um alias para ele. Mas não acho que essa resposta responda à pergunta, pois se tratava de "uma coleção". A menos que você esteja usando um python novo o suficiente para ter o abcmódulo que não é algo que possa ser isinstanceverificado, e mesmo assim eu recomendaria evitar a verificação, se possível.
mzz
1
assert isinstance(u'abc', str) == False. Concordo que é melhor verificar diretamente com o tipo, em vez de usar o typesmódulo, mas types.StringTypesfaz algo que strnão faz: retorna True para stre unicodeobjetos. Vou editar minha resposta para oferecer uma verificação dupla como alternativa.
jcdyer
1
Sei que não respondi à pergunta de procurar coleções diretamente, mas a pergunta real era "É isinstancemau?" E dei um contra-exemplo, do qual (1) é um uso não-mau isinstance, porque ter um fallback significa que não quebra o tipo de pato e (2) é uma boa solução para uma motivação muito comum que as pessoas têm por querer verificar se algo é um listou tuple( ou seja, para desambiguá-los das strings).
jcdyer
Concordo, com a ressalva de que muitas vezes é útil que tipos personalizados também se comportem como strings. Mas OO do Python só vai tão longe ...
Kragen Javier Sitaker
Faz o class Foo(str): passque você quer?
jcdyer
567
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'
wall-e
fonte
1
Parece não funcionar: type ([]) ==> list; tipo ([]) é lista ===> Falso
sten 05/06
3
Em Python 2.7.5: type([]) is listretornosTrue
David Geiger
54
type(x) in [list,tuple]é mais curto.
Alex Holcombe
Se x e tipo (x) é a lista: para evitar o descasamento []
Kenichi Shibata
Eu tive que rolar tanto. : D
Rithwik 19/04/19
38

Não há nada errado em usar isinstance, desde que não seja redundante. Se uma variável deve ser apenas uma lista / tupla, documente a interface e use-a como tal. Caso contrário, um cheque é perfeitamente razoável:

if isinstance(a, collections.Iterable):
    # use as a container
else:
    # not a container!

Esse tipo de verificação possui alguns bons casos de uso, como com a sequência padrão beginwith / endswith methods (embora, para ser preciso, eles sejam implementados em C no CPython, usando uma verificação explícita para verificar se é uma tupla - há mais de uma maneira para resolver esse problema, conforme mencionado no artigo ao qual você vincula).

Uma verificação explícita geralmente é melhor do que tentar usar o objeto como um contêiner e manipular a exceção - isso pode causar todos os tipos de problemas com o código sendo executado parcial ou desnecessariamente.

Scott Griffiths
fonte
15
Essa é uma boa maneira de verificar se uma variável é iterável. No entanto, provavelmente não funcionará para os fins desta pergunta. Esteja ciente de que uma string também é iterável e provavelmente criaria um falso positivo.
Corey O.
Um setobjeto também é iterável, o que significa que, embora você possa seguramente extrair elementos dele, mas não garante uma determinada ordem, o que é uma coisa muito perigosa para certos algoritmos. Nos casos em que a ordem dos elementos é importante, um algoritmo usando esse snippet pode gerar resultados diferentes em execuções diferentes!
koo
14

Documente o argumento como precisando ser uma sequência e use-o como uma sequência. Não verifique o tipo.

Ignacio Vazquez-Abrams
fonte
12

Que tal hasattr(a, "__iter__"):?

Informa se o objeto retornado pode ser iterado como um gerador. Por padrão, tuplas e listas podem, mas não os tipos de sequência.

user1914881
fonte
Eu achei isso realmente útil.
javadba
8
Também resulta em True para strings (pelo menos no Python 3).
SzieberthAdam
2
Esta é uma resposta errada. Como o tipo 'str' também possui o método ' iter '. @SzieberthAdam estava certo. O tipo 'set' também é iterável, mas não pode ser solicitado.
PADYMKO
Também ditados têm __iter__.
thet 30/09
Se você continuar, qualquer tipo personalizado pode ter, __iter__por algum motivo ...
Alexander Irbis
10

Nos type(list) is listretornos do Python 2.8 false
, sugiro comparar o tipo dessa maneira horrível:

if type(a) == type([]) :
  print "variable a is a list"

(pelo menos no meu sistema, usando anaconda no Mac OS X Yosemite)

Xanderite
fonte
1
A lista do tipo (a) é também avaliada como falsa?
Dmitriy Sintsov
4
Você quis dizer Python 2.7.8? python.org/dev/peps/pep-0404/#official-pronouncement
Carl
Olá, estou curioso: por que você considera seu exemplo "horrível"?
Seth Connell
type(list) is listretorna Falseporque type(list)é type, não list. type(list()) is listou com qualquer outra instância de uma lista retornará True.
Michael Greene
8

Python usa "digitação de pato", ou seja, se uma variável kwaks como um pato, deve ser um pato. No seu caso, você provavelmente deseja que seja iterável ou deseja acessar o item em um determinado índice. Você deve fazer o seguinte: ou seja, usar o objeto dentro for var:ou var[idx]dentro de um trybloco e, se você receber uma exceção, não era um pato ...

Wim
fonte
7
O problema é se varuma iteração de sequência ocorrerá com resultados provavelmente inesperados.
Brian M. Caça
Apesar do fato declarado por Brian M. Hunt, é uma solução bastante pitônica, em termos de pedir perdão em vez de permissão.
Géza Török
6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
tetra5
fonte
3

Se você só precisa saber se pode usar a foo[123]notação com a variável, pode verificar a existência de um __getitem__atributo (que é o que python chama quando você acessa por índice) comhasattr(foo, '__getitem__')

Geoff Reedy
fonte
2

Tem que ser um teste mais complexo se você realmente quiser lidar com praticamente qualquer coisa como argumento de função.

type(a) != type('') and hasattr(a, "__iter__")

Embora, geralmente seja suficiente apenas especificar que uma função espera iterável e depois verificar apenas type(a) != type('') .

Também pode acontecer que, para uma string, você tenha um caminho de processamento simples ou que seja legal e faça uma divisão etc., para que não queira gritar com strings e se alguém lhe enviar algo estranho, deixe uma exceção.

ZXX
fonte
2

Outra maneira fácil de descobrir se uma variável é lista ou tupla ou geralmente verifica o tipo de variável seria:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False
mahdi omidiyan
fonte
1

Em princípio, concordo com Ignacio, acima, mas você também pode usar o tipo para verificar se algo é uma tupla ou uma lista.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Adam Crossland
fonte