2017-08-14 67 views
9

Załóżmy następującą funkcję:pythonowy sposobem korzystania z drugiego warunku w listowych

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 

Jak widać, istnieją dwa różne scenariusze w zależności od par1. Nie podoba mi się to, że linia 3 i linia 5 są prawie identyczne i nie przestrzegają zasady DRY (Do not Repeat Yourself). W jaki sposób można poprawić ten kod?

+0

Sprawdź moją odpowiedź, nie mam swoich dokładnych funkcji, więc trudno, aby przetestować go w tym samym środowisku, ale liczyć się powinna rade – dhdavvie

+0

byłoby miło, aby zrozumieć, co rzeczywiście starają się rozwiązać . – ferdy

Odpowiedz

8

Może to działa:

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

tak przyzwyczajeni tak:

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

Możesz również połączyć powrót do linii 2, ale to naprawdę zależy od Ciebie. – dhdavvie

+1

Pomimo tego, że jest to możliwe rozwiązanie, myślę, że czytelność nie jest całkiem dobra, więc brakuje w nim zasady "czytelności" zenu Pythona. IMHO, zrozumienie listy kaskadowej powinno zostać podzielone. – ferdy

+0

Niewielka uwaga: Nie potrzebujesz odwrotnych ukośników w wyrażeniach (lub w nawiasach) :) – MSeifert

8

Można wybrać funkcję warunek dynamicznie przy użyciu funkcji, która po prostu zwraca True w pierwszym przypadku i który faktycznie porównuje wynik my_fun2 z par1 w drugim przypadku:

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)] 

lub przez zastąpienie zewnętrzną pętlę z generator expression w przypadku par1 nie jest pusty ciąg znaków:

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] 

Jednak nie pozwól DRY uczynić funkcja trudniejsze do odczytania, utrzymać lub debug. Osobiście uważam, że twoje podejście jest w porządku (i prawdopodobnie szybciej) i prawdopodobnie nie powinieneś niczego zmieniać.

+2

Dziękuję, tak, zgadzam się. Pomiędzy procesem DRY a czytelnością istnieje cienka linia. – Trarbish

+0

@ Trarbish dobrze, to także pytanie o wydajność (nie tylko o czytelność). Twoje podejście będzie szybsze niż moje podejście do generowania ekspresji (co jest prawdopodobnie najszybszym podejściem DRY, o którym tutaj mowa). – MSeifert

1

dlaczego nie używać filtra?

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

Rozumiem, że dla przyszłości i Python3 zrozumienie list jest lepszym sposobem na poznanie alternatywy użycia mapy, filtrowania i zmniejszania. – madtyn

+0

Filtr w pythonie 3 tworzy generator, dlatego wartość zwracana jest otoczona listą() –