2015-02-07 19 views
9

Oto uproszczony przykład mojego problemu. Myślałem, że te funkcje będą mieć dokładnie ten sam problem:Dziwne zachowanie: operator potrójny dla funkcji

def f1(l): 
    if type(l[0][0])==list: f=lambda x:x[0][0] 
    else: f=lambda x:x[0] 
    l.sort(key=f,reverse=True) 

def f2(l): 
    f=lambda x:x[0][0] if type(l[0][0])==list else lambda x:x[0] 
    l.sort(key=f,reverse=True) 

l=[[1,2],[3,4]] 

Ale w rzeczywistości f1(l) działa poprawnie, gdy f2(l) wali z wyjątkiem:

IndexError: list index out of range 

Więc pytanie jest dlaczego tak jest i czy jest on można użyć potrójnego operatora, który zwraca jedną z funkcji w ogóle?

+1

To jest trochę styczne, ale może jest to jedna z tych sytuacji, w których lambda sprawia, że ​​czytanie jest mniej czytelne niż więcej. Co powiesz na 'def getKey (x):' ​​analizujący 'x' i zwracający' x [0] 'lub' x [0] [0] 'lub cokolwiek potrzebujesz? Następnie 'l.sort (key = getKey, reverse = True)'. –

+0

@Asad Tak, to świetny punkt, chociaż może działać trochę wolniej niż wersja oryginalna. – Nik

+0

Nie jestem pewien, dlaczego widzę, dlaczego byłoby wolniej. Pozwala uniknąć nadmiaru funkcji za każdym razem, gdy wywołujemy 'f1' lub' f2', więc jeśli cokolwiek, byłoby to (nieznacznie) bardziej wydajne. Nie powiedziałbym, że różnica jest warta martwienia się w obu kierunkach. –

Odpowiedz

8

lambda ma lowest precedence among operators. To dlaczego Python analizuje że linia jako

f = lambda x: (x[0][0] if type(l[0][0]) == list else lambda x: x[0]) 

Rozwiązaniem jest owinąć poszczególne lambda S w nawiasach:

f = (lambda x: x[0][0]) if type(l[0][0]) == list else (lambda x: x[0]) 

Powiedział, type(l[0][0]) == list jest trochę źle, isinstance(l[0][0], list) byłby najlepszy sposób (również obsługuje podklasy o wartości list).