Usando ‘in’ para hacer coincidir un atributo de objetos de Python en una matriz

No recuerdo si estaba soñando o no, pero me parece recordar que había una función que permitía algo como,

foo in iter_attr(array of python objects, attribute name) 

He revisado los documentos, pero este tipo de cosas no se incluyen en ningún encabezado obvio.

El uso de una lista de comprensión generaría una lista temporal, que podría consumir toda su memoria si la secuencia que se busca es grande. Incluso si la secuencia no es grande, construir la lista significa iterar sobre toda la secuencia antes in pueda comenzar su búsqueda.

La lista temporal se puede evitar usando una expresión generadora:

 foo = 12 foo in (obj.id for obj in bar) 

Ahora, mientras obj.id == 12 cerca del comienzo de la bar , la búsqueda será rápida, incluso si la bar es infinitamente larga.

Como lo sugirió @Matt, es una buena idea usar hasattr si a alguno de los objetos en la bar puede faltar un atributo de id :

 foo = 12 foo in (obj.id for obj in bar if hasattr(obj, 'id')) 

¿Está buscando obtener una lista de objetos que tienen un determinado atributo? Si es así, una comprensión de la lista es la forma correcta de hacer esto.

 result = [obj for obj in listOfObjs if hasattr(obj, 'attributeName')] 

siempre se puede escribir uno mismo:

 def iterattr(iterator, attributename): for obj in iterator: yield getattr(obj, attributename) 

trabajará con cualquier cosa que itere, ya sea una tupla, una lista o lo que sea.

Me encanta Python, hace que cosas como esta sean muy simples y no más complicadas que las necesarias, y usar cosas como estas es summente elegante.

No, no estabas soñando. Python tiene un excelente sistema de comprensión de listas que te permite manipular las listas de manera bastante elegante, y dependiendo de lo que quieras lograr, esto se puede hacer de varias maneras. En esencia, lo que estás haciendo es decir “Para el ítem en la lista si hay criterios de parches”, y desde ahí puedes simplemente iterar los resultados o volcar los resultados en una nueva lista.

Voy a escribir un ejemplo de Dive Into Python aquí, porque es bastante elegante y son más inteligentes que yo. Aquí están obteniendo una lista de archivos en un directorio, luego filtrando la lista para todos los archivos que coincidan con un criterio de expresión regular.

  files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = [f for f in files if test.search(f)] 

Puede hacer esto sin expresiones regulares, para su ejemplo, para cualquier cosa donde su expresión al final devuelva verdadero para una coincidencia. Hay otras opciones como usar la función de filtro (), pero si fuera a elegir, aceptaría esto.

Eric Sipple

La función que está pensando es probablemente operator.attrgettter . Por ejemplo, para obtener una lista que contenga el valor del atributo “id” de cada objeto:

 import operator ids = map(operator.attrgetter("id"), bar) 

Si desea verificar si la lista contiene un objeto con un id == 12, entonces una forma ordenada y eficiente (es decir, no itera la lista completa innecesariamente) es:

 any(obj.id == 12 for obj in bar) 

Si desea utilizar ‘in’ con attrgetter, mientras sigue manteniendo la iteración perezosa de la lista:

 import operator,itertools foo = 12 foo in itertools.imap(operator.attrgetter("id"), bar) 

Lo que estaba pensando puede lograrse utilizando las listas de comprensión, pero pensé que había una función que hacía esto de una manera ligeramente más ordenada.

es decir, ‘barra’ es una lista de objetos, todos los cuales tienen el atributo ‘id’

La vía mítica funcional:

 foo = 12 foo in iter_attr(bar, 'id') 

La forma de lista de comprensión:

 foo = 12 foo in [obj.id for obj in bar] 

En retrospectiva, la forma de comprensión de la lista es bastante clara de todos modos.

Si planeas buscar algo de un tamaño remotamente decente, lo mejor será usar un diccionario o un juego. De lo contrario, básicamente tienes que recorrer cada elemento del iterador hasta llegar al que deseas.

Si esto no es necesariamente un código sensible al rendimiento, entonces la forma de comprensión de la lista debería funcionar. Pero tenga en cuenta que es bastante ineficiente porque repasa todos los elementos del iterador y luego vuelve sobre él nuevamente hasta que encuentra lo que quiere.

Recuerde, python tiene uno de los algoritmos de hashing más eficientes que existen. Úsalo a tu favor.

Yo creo que:

 #!/bin/python bar in dict(Foo) 

Es en lo que estas pensando. Al tratar de ver si existe una cierta clave dentro de un diccionario en python (versión de python de una tabla hash) hay dos formas de verificar. Primero está el método has_key() adjunto al diccionario y el segundo es el ejemplo dado arriba. Devolverá un valor booleano.

Eso debería responder a su pregunta.

Y ahora, un poco fuera de tema para vincular esto con la lista de respuestas de la respuesta dada anteriormente (para un poco más de claridad). Las Comprensiones de lista construyen una lista a partir de un bucle básico para modificadores. Como ejemplo (para aclarar un poco), una forma de usar el constructo de lenguaje in dict en una lista de comprensión :

Digamos que tienes un diccionario bidimensional y solo quieres los diccionarios de segunda dimensión que contienen la bar teclas. Una forma relativamente sencilla de hacerlo sería utilizar una comprensión de lista con un condicional como sigue:

 #!/bin/python baz = dict([(key, value) for key, value in foo if bar in value]) 

Observe la if bar in value al final de la statement **, esta es una cláusula de modificación que le dice a la lista de comprensión que solo guarde los pares clave-valor que cumplan con el condicional. ** En este caso, baz es un diccionario nuevo que contiene solo los diccionarios de foo que contienen barra (espero que no haya omitido nada en ese ejemplo de código … es posible que tenga que consultar la documentación de comprensión de lista que se encuentra en los tutoriales de docs.python.org y en secnetix.de , ambos Los sitios son buenas referencias si tiene preguntas en el futuro.).