Verifica se una variabile è un elenco o una tupla


234

In Python, qual è il modo migliore per verificare se una variabile contiene un elenco o una tupla? (cioè una collezione)

Il isinstance()male è come suggerito qui? http://www.canonical.org/~kragen/isinstance/

Aggiornamento: il motivo più comune che voglio distinguere un elenco da una stringa è quando ho un albero nidificato indefinitamente profondo / struttura dati di elenchi di elenchi di elenchi di stringhe ecc. Che sto esplorando con un algoritmo ricorsivo e ho bisogno di per sapere quando ho colpito i nodi "foglia".


72
Respingere ampiamente il controllo del tipo come male è un po 'facile. Fa parte della lingua. Se è così male, qualcuno dovrebbe scrivere un PEP per rimuoverlo.
Adam Crossland,

4
@Adam Crossland: "Fa parte della lingua". Proprio come la divisione per zero. È evitabile. In questo caso, senza ulteriori informazioni, è probabilmente completamente inutile. La maggior parte del controllo dei tipi in Python è inutile. Poiché non tutto è inutile, è necessario che sia presente un controllo del tipo. Ma ciò non significa che sia utile, prezioso o addirittura una buona idea.
S. Lott

11
Quindi stai dicendo che è necessario un controllo del tipo, ma nonostante ciò, è inutile, inutile e una cattiva idea. Mi dispiace, non ha proprio senso.
Glenn Maynard,

18
"XXX is evil" è mal concepito, scorciatoia fuorviante per "il modo in cui stai chiedendo di fare XXX suggerisce che non capisci quando dovrebbe effettivamente essere usato e quasi sicuramente vuoi qualcos'altro". Questo è molto probabilmente il caso qui.
Glenn Maynard,

2
Non l'ho ampiamente respinto come malvagio. Ho scritto un breve saggio su quando è malvagio e quando è giustificabile. Quel saggio può essere molte cose - giusto, sbagliato, chiaro, vago, divertente, noioso - ma una cosa che non è è un ampio licenziamento della tecnica.
Kragen Javier Sitaker,

Risposte:


101

Vai avanti e usa isinstancese ne hai bisogno. È in qualche modo malvagio, in quanto esclude sequenze personalizzate, iteratori e altre cose di cui potresti effettivamente aver bisogno. Tuttavia, a volte è necessario comportarsi diversamente se qualcuno, ad esempio, passa una stringa. La mia preferenza sarebbe quella di verificare esplicitamente stro unicodesimili:

import types
isinstance(var, types.StringTypes)

NB non sbaglio types.StringTypeper types.StringTypes. Quest'ultimo incorpora stre unicodeoggetti.

Il typesmodulo è considerato da molti obsoleto a favore del solo controllo diretto rispetto al tipo di oggetto, quindi se preferisci non utilizzare quanto sopra, puoi alternativamente verificare esplicitamente contro stre unicode, in questo modo:

isinstance(var, (str, unicode)):

Modificare:

Meglio ancora è:

isinstance(var, basestring)

Termina modifica

Dopo uno di questi, puoi ricominciare a comportarti come se avessi una sequenza normale, lasciando che le non-sequenze sollevino le opportune eccezioni.

Vedere la cosa "cattiva" nel controllo dei tipi non è che potresti voler comportarti diversamente per un certo tipo di oggetto, è che limiti artificialmente la tua funzione dal fare la cosa giusta con tipi di oggetti inaspettati che altrimenti farebbero la cosa giusta. Se si dispone di un fallback finale che non è stato verificato, si rimuove questa restrizione. Va notato che un eccessivo controllo del tipo è un odore di codice che indica che potresti voler eseguire un refactoring, ma ciò non significa necessariamente che dovresti evitarlo dal getgo.


2
Il modulo types è un po 'un artefatto storico. Come menzionato su docs.python.org/dev/library/types.html#module-types se davvero devi controllare il strtipo, dovresti semplicemente usarlo direttamente, invece di usare types.StringTypequale alias è solo un alias. Ma non credo che questa risposta risponda alla domanda come posta, perché si trattava di "una raccolta". A meno che tu non stia usando un python abbastanza nuovo da avere il abcmodulo che non è qualcosa che puoi usare isinstanceper verificare, e anche allora consiglierei di evitare il controllo se possibile.
mzz

1
assert isinstance(u'abc', str) == False. Sono d'accordo che è meglio verificare direttamente il tipo, piuttosto che usare il typesmodulo, ma types.StringTypesfa qualcosa che strnon lo fa: restituisce True for stre unicodeoggetti. Modificherò la mia risposta per offrire un doppio controllo in alternativa.
jcdyer,

1
Mi rendo conto di non aver risposto alla domanda di controllare direttamente le raccolte, ma la vera domanda posta era "È isinstancecattivo?" E ho dato un contro esempio che (1) è un uso non malvagio isinstance, perché avere un fallback significa che non rompe il ducktyping, e (2) è una buona soluzione per una motivazione molto comune che le persone hanno per voler verificare se qualcosa è un listo tuple(cioè per chiarirli dalle stringhe).
jcdyer,

Sono d'accordo, con l'avvertenza che spesso è utile che anche i tipi personalizzati si comportino come stringhe. Ma la OO di Python va così lontano ...
Kragen Javier Sitaker,

Fa class Foo(str): passquello che vuoi?
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
Sembra non funzionare: tipo ([]) ==> elenco; type ([]) is list ===> False
sten

3
In Python 2.7.5: type([]) is listritorniTrue
David Geiger,

54
type(x) in [list,tuple]è più corto.
Alex Holcombe,

se x e digitare (x) è nell'elenco: per evitare la [] mancata corrispondenza
Kenichi Shibata,

Ho dovuto scorrere così tanto verso il basso. : D
Rithwik,

38

Non c'è niente di sbagliato nell'uso isinstancepurché non ridondante. Se una variabile deve essere solo un elenco / tupla, documenta l'interfaccia e utilizzala come tale. Altrimenti un controllo è perfettamente ragionevole:

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

Questo tipo di controllo presenta alcuni casi d'uso validi, ad esempio con la stringa standard di inizio / fine metodi (anche se per essere precisi questi sono implementati in C in CPython usando un controllo esplicito per vedere se è una tupla - c'è più di un modo per risolvere questo problema, come menzionato nell'articolo a cui ti colleghi).

Un controllo esplicito è spesso meglio che tentare di utilizzare l'oggetto come contenitore e gestire l'eccezione, il che può causare tutti i tipi di problemi con l'esecuzione del codice in parte o inutilmente.


15
Questo è un buon modo per verificare se una variabile è iterabile. Tuttavia, probabilmente non funzionerà ai fini di questa domanda. Tieni presente che anche una stringa è iterabile e probabilmente creerebbe un falso positivo.
Corey O.

Un setoggetto è anche un iterabile, il che significa che mentre puoi sicuramente estrarre elementi da esso, ma non garantisce un certo ordine, il che è una cosa molto pericolosa per alcuni algoritmi. Nei casi in cui l'ordine degli elementi è importante, un algoritmo che utilizza questo frammento potrebbe potenzialmente generare risultati diversi su corse diverse!
koo,

14

Documenta l'argomento come necessità di essere una sequenza e usalo come sequenza. Non controllare il tipo.


12

Che ne dici di hasattr(a, "__iter__"):?

Indica se l'oggetto restituito può essere ripetuto come generatore. Per impostazione predefinita, le tuple e gli elenchi possono, ma non i tipi di stringa.


l'ho trovato davvero utile.
javadba,

8
Risultati anche True per le stringhe (almeno su Python 3).
SzieberthAdam,

2
Questa è una risposta sbagliata Poiché il tipo 'str' ha anche il metodo ' iter '. @SzieberthAdam aveva ragione. Anche il tipo 'set' è iterabile, ma non è ordinabile.
PADYMKO,

Anche i dadi hanno __iter__.
Thet

Se continui, qualsiasi tipo personalizzato potrebbe avere __iter__per qualche motivo ...
Alexander Irbis,

10

Sui type(list) is listrendimenti di Python 2.8 false
suggerirei di confrontare il tipo in questo modo orribile:

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

(bene almeno sul mio sistema, usando anaconda su Mac OS X Yosemite)


1
Il tipo (a) è che anche l'elenco viene valutato come falso?
Dmitriy Sintsov,


Ciao, sono curioso: perché consideri il tuo esempio "orribile"?
Seth Connell,

type(list) is listritorna Falseperché type(list)è type, non è list. type(list()) is listo con qualsiasi altra istanza di un elenco restituirà True.
Michael Greene,

8

Python usa "Duck typing", cioè se una variabile kwaks come un'anatra, deve essere un'anatra. Nel tuo caso, probabilmente desideri che sia iterabile o vuoi accedere all'elemento in un determinato indice. Dovresti semplicemente fare questo: cioè usare l'oggetto dentro for var:o var[idx]dentro un tryblocco, e se ottieni un'eccezione non era un'anatra ...


7
Il problema è che se varsi verifica un'iterazione di stringa con risultati probabilmente imprevisti.
Brian M. Hunt,

Nonostante il fatto dichiarato da Brian M. Hunt, la sua è una soluzione piuttosto pitonica, in termini di chiedere perdono piuttosto che permesso.
Géza Török,

6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True

3

Se hai solo bisogno di sapere se puoi usare la foo[123]notazione con la variabile, puoi verificare l'esistenza di un __getitem__attributo (che è ciò che Python chiama quando accedi per indice) conhasattr(foo, '__getitem__')


2

Deve essere un test più complesso se vuoi davvero gestire qualsiasi cosa come argomento di funzione.

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

Anche se, di solito è sufficiente precisare che una funzione si aspetta iterabile e quindi controllare solo type(a) != type('') .

Inoltre può capitare che per una stringa tu abbia un semplice percorso di elaborazione o che tu sia simpatico e fai una divisione ecc., Quindi non vuoi urlare alle stringhe e se qualcuno ti manda qualcosa di strano, lascia che abbia un'eccezione.


2

Un altro modo semplice per scoprire se una variabile è list o tuple o in generale controllare il tipo di variabile sarebbe:

    def islist(obj):

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

        else : return False

1

In linea di principio, sono d'accordo con Ignacio, sopra, ma puoi anche usare type per verificare se qualcosa è una tupla o un elenco.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.