2009-09-23 30 views
10

Tengo una función que puede incluir un número o una lista de números. ¿Cuál es la forma más pitónica de verificar cuál es? Hasta ahora he llegado a probar/excepto bloquear si puedo cortar el elemento cero, es decir. obj [0: 0]¿Cuál es la forma pitónica de verificar si un objeto es una lista?

Editar:

que parecen haber comenzado una guerra de palabras por debajo por no dar suficiente información. Para completar, permítanme proporcionar más detalles para poder elegir la mejor respuesta para mi situación:

Estoy ejecutando Django en Python 2.6 y estoy escribiendo una función que puede tomar una instancia de modelo de Django o una queryset object y realizar operaciones en ella, una de las cuales implica usar el filtro 'in' que requiere una lista (la entrada queryset), o alternativamente si no es una lista, entonces usaría el filtro 'get' (el filtro django get) .

+0

@mog: Por favor, acepte una respuesta, en lugar de dejar la pregunta pendiente. –

Respuesta

21

En tales situaciones, que normalmente tienen que comprobar que no existen iterable, no sólo enumera - si usted está aceptando las listas o números, el rechazo (por ejemplo) una tupla sería extraño. El único tipo de iterable que puede tratar como un "escalar" es una cadena - en Python 2. *, esto significa str o unicode. Por lo tanto, ya sea:

def isNonStringIterable(x): 
    if isinstance(x, basestring): 
    return False 
    try: iter(x) 
    except: return False 
    else: return True 

o, por lo general mucho más práctico:

def makeNonStringIterable(x): 
    if isinstance(x, basestring): 
    return (x,) 
    try: return iter(x) 
    except: return (x,) 

donde se acaba de ir for i in makeNonStringIterable(x): ...

+1

Este es el enfoque correcto, pero utilizando las herramientas incorrectas. –

+14

@gs, dado que he sido un committer de Python durante 8 años (y he escrito libros populares, etc. en Python), me gustaría que me enseñaras cómo estoy usando las "herramientas incorrectas" de todos esos Ayudé a diseñar, implementar, documentar, etc. Seguramente no (pensando en su ampliamente rechazada respuesta) al no usar 'collections.Sequence' (que descartaría' set' sin ninguna BUENA razón), por ejemplo - ¿DERECHO? -) –

+0

Entrada de la lista de correo de Python para determinar si un objeto es iterable: http://mail.python.org/pipermail/python-list/2006-July/566226.html –

1

Se puede utilizar para comprobar isinstance un tipo de variables:

if isinstance(param, list): 
    # it is a list 
    print len(list) 
+0

Esta solución evita cualquier lista personalizada que no sea subclases de la lista. –

-3

sólo tiene que utilizar el método de tipo? O estoy malinterpretando la pregunta

if type(objectname) is list: 
    do something 
else: 
    do something else :P 
+1

Esta es una mala solución. Una mejor forma es isinstance() porque esto también permite subclases. –

11

No es así.

Esto funciona solo para Python> = 2.6. Si tiene como objetivo algo inferior, use Alex' solution.

Python es compatible con algo llamado Duck Typing. Puede buscar cierta funcionalidad usando el ABC classes.

import collections 
def mymethod(myvar): 
    # collections.Sqeuence to check for list capabilities 
    # collections.Iterable to check for iterator capabilities 
    if not isinstance(myvar, collections.Iterable): 
     raise TypeError() 
+0

¿alguien podría explicar los votos a favor? Esto parece sensato, ya que ser una "lista" es mucho menos interesante que ser "listy". –

+0

Esta es la respuesta más correcta aquí, lo que explica el downvote. (Sí, estoy siendo un poco sarcástico, el sistema de votación en este sitio es horrible.) No se le debe permitir votar en voz baja sin hacer ningún comentario. –

+0

@ Daren: edité mi respuesta bastante. (Todavía creo que la primera versión no era tan mala) –

13
if isinstance(your_object, list): 
    print("your object is a list!") 

Esto es más Pythonic de comprobar con el tipo.

parece más rápido también:

>>> timeit('isinstance(x, list)', 'x = [1, 2, 3, 4]') 
0.40161490440368652 
>>> timeit('type(x) is list', 'x = [1, 2, 3, 4]') 
0.46065497398376465 
>>> 
+0

Debo mencionar que utilicé "tipo (x) es lista", y no solo "tipo (x)" porque ambos deberían devolver el mismo valor (Verdadero) para que la comparación sea justa. – Vince

+4

Esta solución impide que las listas personalizadas que no son subclases de la lista. –

+1

@gs: Tienes razón. Su solución a continuación es una buena solución limpia (creo que es la más limpia de la página si, de hecho, el OP deseaba usar iterables "detallados" en lugar de solo una instancia de lista). Parte del problema está en la ambigüedad de OP. Si está probando si los objetos queryset son listas, simplemente debería verificar si es una instancia de QuerySet y luego usar len(). Si está probando si el parámetro 'field__in' es una lista, mi solución funcionará. Si ese parámetro es más flexible, debe elegir su solución. – Vince

2

no quiero ser una plaga, pero: ¿Estás seguro de la consulta set/object es una buena interfaz? Realiza dos funciones, como:

def fobject(i): 
    # do something 

def fqueryset(q): 
    for obj in q: 
     fobject(obj) 

podría no ser el Pythonic forma de discernir un int de una lista, pero parece mucho mejor diseño para mí.

Razón siendo: Su función debería estar funcionando en patos. Mientras grazna, golpéalo.En realidad, levantar el pato, ponerlo boca abajo para verificar las marcas en el vientre antes de elegir el palo adecuado para golpear es unpythonic. Lo siento. Solo no vayas allí.

+0

alerta no epistónica! etiquetas separadas a menos que OP quiera hacer cosas totalmente diferentes basadas en objetos, deben ser la misma función –

+1

No estoy tan seguro acerca de la alerta unpythonic: si tiene que discernir en función del tipo de objeto (lista vs. int), entonces * están * haciendo "cosas totalmente diferentes basadas en el objeto". –

+0

+1: El diseño original (una función que hace dos cosas por separado) es realmente pobre. Esta es claramente una función para objetos * y una función separada * para conjuntos de consultas de objetos. –

0

Creo que la forma en que OP está haciendo, comprobando si es compatible con lo que quiere, está bien.

Manera más simple en este escenario sería no verificar la lista que puede ser de muchos tipos dependiendo de la definición, puede verificar si la entrada es número, hacer algo al respecto intentar usarlo como lista si eso arroja una excepción fuera.

por ejemplo, puede que no desee iterar sobre la lista pero sólo quería añadir algo a ella si es lista, y añadir a ella

def add2(o): 
    try: 
     o.append(2) 
    except AttributeError: 
     o += 2 

l=[] 
n=1 
s="" 
add2(l) 
add2(n) 
add2(s) # will throw exception, let the user take care of that ;) 

Así que la línea inferior es la respuesta puede variar dependiendo de lo que quiere hacer con objeto

+0

Su ejemplo no funciona porque los números son inmutables en python. –

+0

que es un ejemplo y a qué te refieres con que no funciona, ¿quién te dijo el propósito de la función add2, para que puedas deducir que no funciona? puede ser solo quiero consumir algo de CPU agregando enteros –

Cuestiones relacionadas