separar - ¿Cómo puedo saber si una variable de python es una cadena o una lista?
string en python (8)
Tengo una rutina que toma una lista de cadenas como parámetro, pero me gustaría admitir pasar una sola cadena y convertirla en una lista de una cadena. Por ejemplo:
def func( files ):
for f in files:
doSomethingWithFile( f )
func( [''file1'',''file2'',''file3''] )
func( ''file1'' ) # should be treated like [''file1'']
¿Cómo puede mi función indicar si se ha pasado una cadena o una lista? Sé que hay una función type
, pero ¿hay una forma "más pythonic"?
Bueno, no hay nada antipático sobre verificar el tipo. Habiendo dicho eso, si está dispuesto a poner una pequeña carga en la persona que llama:
def func( *files ):
for f in files:
doSomethingWithFile( f )
func( *[''file1'',''file2'',''file3''] ) #Is treated like func(''file1'',''file2'',''file3'')
func( ''file1'' )
Yo diría que esto es más pitónico porque "lo explícito es mejor que lo implícito". Aquí hay al menos un reconocimiento por parte de la persona que llama cuando la entrada ya está en forma de lista.
Personalmente, realmente no me gusta este tipo de comportamiento, ya que interfiere con el tipado de patos. Se podría argumentar que no obedece al mantra "lo explícito es mejor que lo implícito". ¿Por qué no usar la sintaxis varargs?
def func( *files ):
for f in files:
doSomethingWithFile( f )
func( ''file1'', ''file2'', ''file3'' )
func( ''file1'' )
func( *listOfFiles )
Si tiene más control sobre la persona que llama, entonces una de las otras respuestas es mejor. No tengo ese lujo en mi caso, así que decidí la siguiente solución (con salvedades):
def islistlike(v):
"""Return True if v is a non-string sequence and is iterable. Note that
not all objects with getitem() have the iterable attribute"""
if hasattr(v, ''__iter__'') and not isinstance(v, basestring):
return True
else:
#This will happen for most atomic types like numbers and strings
return False
Este enfoque funcionará para casos en los que esté tratando con un conjunto conocido de tipos similares a listas que cumplan con los criterios anteriores. Sin embargo, algunos tipos de secuencia se perderán.
Varargs fue confuso para mí, así que lo probé en Python para aclararlo por mí mismo.
Antes que nada, el PEP para varargs está here .
Aquí hay un programa de muestra, basado en las dos respuestas de Dave y David Berger, seguido de la salida, solo para aclarar.
def func( *files ):
print files
for f in files:
print( f )
if __name__ == ''__main__'':
func( *[''file1'',''file2'',''file3''] ) #Is treated like func(''file1'',''file2'',''file3'')
func( ''onestring'' )
func( ''thing1'',''thing2'',''thing3'' )
func( [''stuff1'',''stuff2'',''stuff3''] )
Y la salida resultante;
(''file1'', ''file2'', ''file3'')
file1
file2
file3
(''onestring'',)
onestring
(''thing1'', ''thing2'', ''thing3'')
thing1
thing2
thing3
([''stuff1'', ''stuff2'', ''stuff3''],)
[''stuff1'', ''stuff2'', ''stuff3'']
Espero que esto sea útil para otra persona.
Yo diría que la forma más fácil de Python es hacer que el usuario siempre pase una lista, incluso si solo hay un elemento en ella. Lo hace realmente obvio func()
puede tomar una lista de archivos
def func(files):
for cur_file in files:
blah(cur_file)
func([''file1''])
Como Dave sugirió, podría usar la sintaxis func(*files)
, pero nunca me gustó esta característica, y parece más explícita ("explícita es mejor que implícita") para simplemente requerir una lista. También está convirtiendo su caso especial (llamando a func
con un único archivo) en el caso predeterminado, porque ahora tiene que usar sintaxis adicional para llamar a func
con una lista.
Si desea crear un caso especial para que un argumento sea una cadena, use el isinstance()
incorporado y compare con la basestring
de basestring
(de la cual se derivan str()
y unicode()
), por ejemplo:
def func(files):
if isinstance(files, basestring):
doSomethingWithASingleFile(files)
else:
for f in files:
doSomethingWithFile(f)
Realmente, sugiero simplemente requerir una lista, incluso con un solo archivo (¡después de todo, solo requiere dos caracteres adicionales!)
def func(files):
for f in files if not isinstance(files, basestring) else [files]:
doSomethingWithFile(f)
func([''file1'', ''file2'', ''file3''])
func(''file1'')
if hasattr(f, ''lower''): print "I''m string like"
isinstance(your_var, basestring)