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".


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.


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'

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.


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.


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.


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)


1
A lista do tipo (a) é também avaliada como falsa?
Dmitriy Sintsov


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


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

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


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.


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

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')
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.