2009-12-11 3 views
1

Этот код кажется запах:Является ли эта структура управления запахом кода?

result = None 
for item in list: 
    if result is None: 
     result = item.foo(args) 
    else: 
     if ClassFred.objects.get(arg1=result) < ClassFred.objects.get(arg1=item.foo(args)): 
      result = item.foo(args) 

smelliest часть полезность «результата». Кто-нибудь будет любезно понюхать его для меня?

+1

вы пытаетесь получить «минимальное» значение? –

+0

Правильно! Очень проницательный для вас :) ClassFred - это класс заказа, но не полностью для заказа; поэтому я переименовал его. +1 для того, чтобы исследовать мой мозг и заставлять меня думать! :) – Alex

+0

Все желающие +1 Отличный ответ Роджера Пате, это отличное объяснение с отличными примерами кода для тех, кто пытается понять функцию лямбда :) – Alex

ответ

3
L = list # 'list' is a poor variable name, use something else 
result = min((n.foo(args) for n in L), 
      key=lambda x: ClassFred.objects.get(arg1=x)) 
# if you don't have to use arg1 as a named parameter: 
result = min((n.foo(args) for n in L), key=ClassFred.objects.get) 

Минимальная функция сравнивает данные элементы и возвращает минимальное один (конечно: P). Вначале не очевидно, что вы можете контролировать, какое значение используется для их сравнения, это параметр «ключ».

>>> L = [-2, -1, 3] 
>>> min(L) 
-2 
>>> min(L, key=abs) 
-1 

Ключевая функция вычисляет «сравнительный ключ», и это то, что используется для сравнения. Ключевая функция по умолчанию - это идентификатор, где ключ сравнения для элемента является самим элементом.

>>> def identity(x): 
... return x 
>>> min(L, key=identity) 
-2 

Другой пример:

>>> min("0000", "11", "222", "3") 
"0000" # lexicographical minimum 
>>> min("0000", "11", "222", "3", key=len) 
"3" 

Ваш код выше использует item.foo(args) в качестве значений, где элемент приходит из списка; но для сравнения используется результат прохождения через ClassFred.objects.get(arg1=..). Это означает, что конструкция является вашей ключевой функцией:

values = (n.foo(args) for n in L) # this is a generator expression 
# it is similar to a list comprehension, but doesn't compute or store 
# everything immediately 

def keyfunc(x): 
    return ClassFred.objects.get(arg1=x) 

result = min(values, key=keyfunc) 

Мой код в верхней части просто объединяет это в одном заявлении.

+0

Я могу заверить, что я не использую список как имя переменной :) Я просто уменьшил свой код, чтобы его было легче читать, и есть только один список. В качестве параметра требуется параметр arg1. Фактически, в моем реальном коде есть фактически 2 аргумента, и это снова было уменьшено для удобочитаемости. Я не мог заставить это работать, но +1, потому что я думаю, что функция min будет неплохо использовать здесь, поскольку я на самом деле пытаюсь найти минимальное значение. Я попытаюсь заставить его работать после выходных :), поскольку у меня не хватило времени, пытаясь заставить эту запутанную функцию лямбда работать! Еще раз спасибо. – Alex

+0

Вы используете «список» в качестве имени переменной в своем вопросе. Если вы публикуете свой реальный код, то, возможно, я смогу понять, как это было неверно представлено в первоначальном тестовом примере выше. Любая лямбда может быть переписана с помощью инструкции def, которую я отредактирую, чтобы показать это. – 2009-12-11 06:59:08

+0

result = min (ClassFred.objects.get (arg1 = x) для x в списке) – 2009-12-11 07:10:55

1

Логика слишком сложна. Трудно прочитать, что вы на самом деле делаете. Упростите этот цикл, вы делаете слишком много там.

Это ИМХО уже довольно неприятный запах.

+1

Разве это не просто вопрос? Он знает, что он пахнет и пытается его улучшить. – 2009-12-11 06:08:12

1

Вторая до последней линии так долго, что я потерял терпение. Я бы сделал эти две отдельные переменные со значимыми именами, поэтому мы можем понять, что, если предполагается x < y.

Как об этом:

if not list: 
    return None 

def get_thing(bar): 
    # I don't know what this is, so... here: 
    return ClassFred.objects.get(arg1=bar.foo(args)) 

# way less hassle than that if-else stuff 
biggest = get_thing(list[0]) 
for item in list: 
    current = get_thing(item) 
    if biggest < current: 
      biggest = current 
+0

Спасибо, что нашли время, чтобы понять это :) Мне очень нравится ваш ответ, поэтому +1, но теперь я верю, что искал сращивание массивов! – Alex

1

Итак, я согласен, кажется, что он может быть реорганизован с точки зрения удобочитаемости, но он должен работать. Это было бы мое взятие на нем:

# using lst instead of list & at least python 2.5 
result = lst[0].foo(args) if lst else None 
fxn = ClassFred.objects.get 

for item in lst[1:]: 
    if fxn(arg1=result) > fxn(arg1=item.foo(args)): 
     result = item.foo(args) 
+0

Array splicing - это то, что я искал, так +1 :) Спасибо! Просто позвольте мне проверить это сложное перспективное лямбда-решение выше. – Alex

+0

Хе-хе ... у вашего оператора «<» стоит обратный путь! Все в порядке, хотя я прощаю ya :) Это хорошо работает, так что спасибо. На этой неделе у меня не хватило времени, чтобы найти, какой ответ лучше, поэтому мне придется отвечать в понедельник. Сожалею! – Alex

+0

Ой, я пойду вперед и переверну это. ;) –

0

Это может работать, хотя, я не думаю, что это будет лучше пахнут: р

max([ClassFred.objects.get(arg1=item.foo(args)), item.foo(args) for item in list])[1] 
Смежные вопросы