Domanda

Non ricordo se stavo sognando o no, ma mi sembra di ricordare che esistesse una funzione che permettesse qualcosa del tipo:

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

Ho esaminato i documenti, ma questo genere di cose non rientra in alcuna intestazione elencata ovvia

È stato utile?

Soluzione

L'utilizzo di una comprensione di elenco creerebbe un elenco temporaneo, che potrebbe consumare tutta la memoria se la sequenza da cercare è grande.Anche se la sequenza non è grande, costruire l'elenco significa ripetere prima l'intera sequenza in potrebbe iniziare la sua ricerca.

L'elenco temporaneo può essere evitato utilizzando un'espressione generatrice:

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

Ora, purché obj.id == 12 vicino all'inizio di bar, la ricerca sarà veloce, anche se bar è infinitamente lungo.

Come suggerito da @Matt, è una buona idea da usare hasattr se uno qualsiasi degli oggetti in bar può mancare un id attributo:

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

Altri suggerimenti

Stai cercando di ottenere un elenco di oggetti che hanno un determinato attributo?Se è così, a comprensione delle liste è il modo giusto per farlo.

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

potresti sempre scriverne uno tu stesso:

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

funzionerà con qualsiasi cosa che itera, sia essa una tupla, una lista o qualsiasi altra cosa.

Adoro Python, rende cose come questa molto semplici e non più una seccatura che necessarie, e nell'uso cose come questa sono estremamente eleganti.

No, non stavi sognando.Python ha un sistema di comprensione delle liste piuttosto eccellente che ti consente di manipolare le liste in modo piuttosto elegante e, a seconda di cosa esattamente vuoi ottenere, questo può essere fatto in un paio di modi.In sostanza, quello che stai facendo è dire "Per l'elemento nell'elenco se criteri.corrisponde" e da ciò puoi semplicemente scorrere i risultati o scaricare i risultati in un nuovo elenco.

Prenderò un esempio da Immergiti in Python qui, perché è piuttosto elegante e loro sono più intelligenti di me.Qui ottengono un elenco di file in una directory, quindi filtrano l'elenco per tutti i file che corrispondono ai criteri di un'espressione regolare.

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

Potresti farlo senza espressioni regolari, per il tuo esempio, per qualsiasi cosa in cui la tua espressione alla fine restituisce true per una corrispondenza.Ci sono altre opzioni come usare la funzione filter(), ma se dovessi scegliere, sceglierei questa.

Eric Sipple

La funzione a cui stai pensando è probabilmente operator.attrgettter.Ad esempio, per ottenere un elenco che contiene il valore dell'attributo "id" di ciascun oggetto:

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

Se vuoi verificare se l'elenco contiene un oggetto con un id == 12, allora un metodo pulito ed efficiente (cioènon ripete l'intero elenco inutilmente) il modo per farlo è:

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

Se vuoi usare 'in' con attrgetter, pur mantenendo l'iterazione pigra dell'elenco:

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

Ciò a cui stavo pensando può essere ottenuto utilizzando la comprensione delle liste, ma pensavo che esistesse una funzione che lo facesse in un modo leggermente più ordinato.

cioè.'bar' è un elenco di oggetti, tutti con l'attributo 'id'

Il mitico modo funzionale:

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

Il modo di comprensione dell'elenco:

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

In retrospettiva, il modo di comprendere l'elenco è comunque abbastanza accurato.

Se hai intenzione di cercare qualcosa di dimensioni decenti, la soluzione migliore sarà utilizzare un dizionario o un set.Altrimenti, devi praticamente scorrere ogni elemento dell'iteratore fino ad arrivare a quello che desideri.

Se questo non è necessariamente un codice sensibile alle prestazioni, allora il metodo di comprensione dell'elenco dovrebbe funzionare.Ma tieni presente che è abbastanza inefficiente perché esamina ogni elemento dell'iteratore e poi lo torna indietro finché non trova ciò che vuole.

Ricorda, Python ha uno degli algoritmi di hashing più efficienti in circolazione.Usalo a tuo vantaggio.

Penso:

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

È quello a cui stai pensando.Quando si tenta di vedere se una determinata chiave esiste all'interno di un dizionario in Python (la versione di Python di una tabella hash) ci sono due modi per verificare.Il primo è il has_key() metodo allegato al dizionario e il secondo è l'esempio riportato sopra.Restituirà un valore booleano.

Questo dovrebbe rispondere alla tua domanda.

E ora un po' fuori tema per collegare questo al comprensione delle liste risposta data in precedenza (per un po' più di chiarezza). Elenco comprensioni costruire un elenco da una base per ciclo con modificatori.Ad esempio (per chiarire un po'), un modo di utilizzare il file in dict costrutto linguistico in a comprensione delle liste:

Supponiamo che tu abbia un dizionario bidimensionale foo e vuoi solo i dizionari della seconda dimensione che contengono la chiave bar.Un modo relativamente semplice per farlo sarebbe utilizzare a comprensione delle liste con il condizionale così:

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

Notare la if bar in value alla fine dell'istruzione**, questa è una clausola modificativa che dice a comprensione delle liste per mantenere solo le coppie chiave-valore che soddisfano il condizionale.** In questo caso baz è un nuovo dizionario che contiene solo i dizionari di foo che contengono bar (spero di non aver perso nulla in quell'esempio di codice...potresti dover dare un'occhiata alla documentazione di comprensione dell'elenco trovata in tutorial su docs.python.org e a secnetix.de, entrambi i siti sono buoni riferimenti se avete domande in futuro.).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top