2017-08-14 1 views
9

Supposons que la fonction suivante:façon Pythonic d'utiliser la deuxième condition dans la liste compréhensions

def myfun(my_list, n, par1=''): 
    if par1 == '': 
     new_list = [[my_fun2(i,j) for j in range(n)] for i in range(n)] 
    else: 
     new_list = [[my_fun2(i,j) for j in range(n)] for i in range(n) if my_fun2(i,n) == par1] 
    return new_list 

Comme vous pouvez le voir, il y a deux scénarios différents selon par1. Je n'aime pas que la ligne 3 et la ligne 5 soient presque identiques et ne suivent pas le principe DRY (Do not Repeat Yourself). Comment ce code peut-il être amélioré?

+0

Vérifiez ma réponse, je n'ai pas vos fonctions exactes de sorte qu'il est difficile de le tester dans le même environnement, mais je pense qu'il devrait faire l'affaire – dhdavvie

+0

Ce serait bien de comprendre ce que vous essayez réellement de résoudre . – ferdy

Répondre

8

Cela pourrait fonctionner:

new_list = [[my_fun2(i,j) for j in range(n)] for i in range(n) if par1 == '' or my_fun2(i,n) == par1] 

donc utilisé comme ceci:

def myfun(my_list, n, par1=''): 
    return [ 
       [my_fun2(i,j) for j in range(n)] 
       for i in range(n) if par1 == '' or my_fun2(i,n) == par1 
      ] 
+0

Vous pouvez également fusionner le retour dans la ligne 2, mais c'est vraiment à vous – dhdavvie

+1

Malgré cette solution possible, je pense que la lisibilité n'est pas très bonne, donc il manque la règle de "lisibilité compte" du zen de python. À mon humble avis la compréhension de la liste en cascade devrait être divisé. – ferdy

+0

Note mineure: Vous n'avez pas besoin des barres obliques inverses à l'intérieur des phrases (ou entre parenthèses) :) – MSeifert

8

Vous pouvez choisir la fonction de condition dynamique à l'aide d'une fonction qui retourne juste True dans le premier cas et qui fait compare le résultat my_fun2 avec par1 dans le second cas:

def myfun(my_list, n, par1=''): 
    if par1 == '': 
     cond = lambda x, y: True 
    else: 
     cond = lambda i, n: my_fun2(i, n) == par1 
    return [[my_fun2(i,j) for j in range(n)] for i in range(n) if cond(i,n)] 

ou en remplaçant la boucle extérieure avec un generator expression en cas par1 n'est pas une chaîne vide:

def myfun(my_list, n, par1=''): 
    if par1 == '': 
     outer = range(n) 
    else: 
     # a conditional generator expression 
     outer = (i for i in range(n) if my_fun2(i,n) == par1) 
    return [[my_fun2(i,j) for j in range(n)] for i in outer] 

Cependant ne font pas laisser sécher la fonction plus difficile à lire, maintenir ou débogage. Personnellement, je pense que votre approche est bonne (et probablement plus rapide) et vous ne devriez probablement rien changer.

+2

Merci, oui, je suis d'accord. Il y a une ligne fine entre DRY et lisibilité. – Trarbish

+0

@Trarbish bien, c'est aussi une question de performance (pas seulement sur la lisibilité). Votre approche sera plus rapide que mon approche d'expression de générateur (qui est probablement l'approche la plus rapide non DRY mentionnée ici). – MSeifert

1

pourquoi ne pas utiliser un filtre?

from operator import eq 
def myfun(my_list, n, par1=''): 
    new_list = ([my_fun2(i,j) for j in range(n)] for i in range(n)) 
    if par1 != '': 
     new_list = filter(eq(par1),new_list) 
    return list(new_list) 
+1

Je comprends que pour le futur et Python3, les compréhensions de listes sont une meilleure façon de passer en revue l'alternative d'utiliser map, filter et reduce. – madtyn

+0

Filtrer en python 3 crée un générateur, c'est pourquoi la valeur de retour est entourée d'une liste() –