2013-05-07 4 views
9

Normalmente so che possiamo fare sum([func(x,x) for x in i]), ma ho ottenuto un controllo if e due loop, quindi qual è il modo più poderoso di scrivere il codice qui sotto. puoi presumere che la somiglianza restituirà un numero indipendentemente dal tipo che gli dai. Puoi anche presumere che in realtà otterrà solo interi e caratteri.Python, il modo migliore per scrivere una somma di due per loop

x = 0 
if isinstance(a, dict) or isinstance(a, list) or isinstance(a, tuple): 
    for i in a: 
     for j in b: 
      x += similarity (i,j) 
+5

Il 'if' non è all'interno di alcun ciclo, quindi ... perché deve essere all'interno della' somma'? – abarnert

+1

Per il tuo esempio, invece della comprensione della lista di 'sum ([func (x, y) per x in i])' puoi usare 'sum (func (x, y) per x in i)' come generatore e non generare l'elenco intermedio –

risposta

10

Forse qualcosa di simile:

x=0 
if isinstance(a,(dict,list,tuple)): 
    x=sum(similarity(i,j) for i in a for j in b) 

Oppure:

x=(sum(similarity(i,j) for i in a for j in b) if isinstance(a,(dict,list,tuple)) 
    else 0) 

O (supponendo che una stringa, set o qualche altro tipo iterabile non interrompe la funzione per qualche motivo):

try: 
    x=sum(similarity(i,j) for i in a for j in b) 
except TypeError: 
    x=0 

Se sono specificamente cercando di verificare se qualcosa è iterabile, si può fare in questo modo:

from collections import Iterable 
if isinstance(e, Iterable): 
    ... 

Se ci sono alcuni tipi iterabili che non si desidera, reagiscono a quelle:

if isinstance(e, Iterable) and not isinstance(el, str): 
    # an iterable that is not a string... 
+5

Non c'è motivo per usare 'any' con' isinstance', quando puoi semplicemente passare tutti i tipi a 'isinstance' stessa. – abarnert

+0

OK - grazie. Buona pesca. Modifica fatta – dawg

+1

Downvoter - Posso chiedere perché? Ho apportato la modifica suggerita .. – dawg

5

Dal momento che il if non è all'interno di un ciclo, non ha bisogno di essere dentro la lista di comprensione quando si converte:

x = 0 
if isinstance(a, dict) or isinstance(a, list) or isinstance(a, tuple): 
    x = sum([similarity(i, j) for i in a for j in b]) 

Nel frattempo, davvero non hanno bisogno di una lista la comprensione qui, un generatore di espressione avrà lo stesso effetto senza dover costruire una lista:

x = 0 
if isinstance(a, dict) or isinstance(a, list) or isinstance(a, tuple): 
    x = sum(similarity(i, j) for i in a for j in b) 

Nel frattempo, isinstance può prendere una tuple di tipi per controllare, in modo da:

x = 0 
if isinstance(a, (dict, list, tuple)): 
    x = sum(similarity(i, j) for i in a for j in b) 

... ma in realtà, non credo che si desidera controllare in primo luogo. Finché a è qualsiasi iterabile, il codice funzionerà, quindi ... perché dovrei costringerlo a essere quei tipi specifici? Se non si vuole un'eccezione, basta gestire l'eccezione:

try: 
    x = sum(similarity(i, j) for i in a for j in b)) 
except TypeError: 
    x = 0 
+0

@DSM: Sì, la mia risposta lo dice già. Ma davvero, non dovrebbe usarlo affatto, come ho spiegato nella modifica. (In ogni caso, non è rilevante per la domanda principale che stava chiedendo.) – abarnert

+0

La prima versione aveva la frase "Nel frattempo,' isinstance' può prendere una 'tupla' di tipi da controllare, ma in realtà, perché bisogno di controllare a tutti? " Ho ampliato la prima parte nella prima modifica e la seconda nella seconda modifica. – abarnert

+0

+1 per l'idioma [EAFP] (http://docs.python.org/2/glossary.html#term-eafp). – Johnsyweb

0
if type(a) in [dict, list, tuple]: 
    x += sum(similarity(i, j) for i in a for j in b) 

sì, tipo non è lo stesso di isistance ma non è un problema drammatico ..

se l'OP volesse usare quel pezzo di codice con qualcosa che assomiglia a dict, list o tuples (quindi con sottoclassi e tutto), dovrebbe davvero controllare che l'a sia iterable.

qualcosa di simile:

def isiterable(obj): 
    try: 
     iter(obj) 
     return True 
    except TypeError: 
     return False 

if isiterable(a): 
    x += sum(similarity(i, j) for i in a for j in b) 
+7

usando 'type' non è la stessa cosa di 'isinstance', e non è una buona idea – cmd

+1

Ok domanda stupida, perché no? – EasilyBaffled

+0

@EasilyBaffled: Cosa succede se passo in qualcosa che è un'istanza di una sottoclasse di 'dict'? Funzionerà con 'isinstance', ma non funzionerà con il controllo esplicito di' type'. – abarnert

9

probabilmente si desidera qualcosa di simile:

if isinstance(a, (dict, list, tuple)): 
    x = sum(similarity(i, j) for i in a for j in b) 
else: 
    x = 0 
+1

Perché questo è stato downvoted? È vero, non aggiunge nulla che non fosse già presente in almeno 2 risposte preesistenti, ma da quando questa è una ragione di downvote? – abarnert

+0

Non ho idea del downvote, ma di "difendere" la risposta: quando è stata scritta, nessun'altra risposta ha passato una tupla a 'isinstance', né ha mostrato che' sum' è impostato su 0, il che rende superfluo un compito incondizionato. Inoltre, alcune delle risposte esistenti erano inutilmente prolisse. – user4815162342

+0

Data la scelta di spiegare i cambiamenti che l'OP è improbabile da capire, rispetto a dargli un codice che apparentemente fa ciò che vuole per magia in modo che possa caricare il suo modo di codificare che non può mantenere o addirittura eseguire il debug, non lo faccio Penso che il primo sia "troppo verboso". (Inoltre, la mia risposta è stata la prima e, sebbene non abbia usato _show_ usando 'isinstance' con una tupla, ha avuto la stessa informazione:" Nel frattempo, 'isinstance' può prendere una' tupla' di tipi da controllare ... "Non l'ho mostrato perché pensavo fosse meglio mostrare che non aveva affatto bisogno di controllare i caratteri.) – abarnert

1

In una riga;)

x = sum(similarity(i, j) for i in a for j in b) if isinstance(a, (dict, list, tuple)) else 0 
+5

"[Readability counts] (http://www.python.org/dev/peps/pep-0020/)" – Johnsyweb

+1

Ovviamente ... Ecco perché ho messo la faccina lì dentro;) – tamasgal

+1

L'OP non ha richiesto il codice golf. – abarnert

7

Si potrebbe utilizzare alcune funzioni da itertools, forse:

from itertools import starmap, product 
x = sum(starmap(similarity, product(a, b))) 

e come altri hanno notato, può anche passare una tupla di tipi di isinstance() se si ha realmente bisogno di controllare.

+0

+1 per itertools-foo – user4815162342

Problemi correlati