2013-11-07 3 views
1

У меня есть этот блок кода в реальной функции Django. Если выполнены определенные условия, элементы добавляются к list.Существует ли «Pythonic» способ создания списка с условными элементами?

ret = [] 

if self.taken(): 
    ret.append('taken') 

if self.suggested(): 
    ret.append('suggested') 

#.... many more conditions and appends... 

return ret 

Это очень функциональный . Вы знаете, что он делает, и это здорово ...
Но я научился ценить красоту list и dict соображений.

Есть ли еще Pythonic способ формулировки этой конструкции, возможно, которая инициализирует и заполняет массив одним ударом?

ответ

1

Для этого очень специфический Например, я мог бы сделать:

return [x for x in ['taken', 'suggested', ...] if getattr(self, x)()] 

Но опять же, это только работы, где элемент и способ его звонки, чтобы проверить имеют одинаковое имя, то есть для моего точного кода , Его можно было адаптировать, но он немного твердый. Я очень открыт для других решений!

1

Не большой шаг вперед, но я буду говорить об этом:

def populate(): 
    if self.taken(): 
     yield 'taken' 
    if self.suggested(): 
     yield 'suggested' 

ret = list(populate()) 

Можем ли мы сделать лучше? Я скептически настроен. Очевидно, что нужно использовать другой синтаксис, чем литерал списка, потому что у нас больше нет инварианта «1 выражение = 1 в результате».


Edit:

Там в шаблон нашим данным, и это список пар (состояние, значение). Мы могли бы попытаться использовать его с помощью:

[value 
for condition, value 
in [(self.taken(), 'taken'), 
    (self.suggested(), 'suggested')] 
if condition] 

, но это по-прежнему является ограничением для того, как вы опишете вашу логику, все еще имеет неприятный побочный эффект оценки всех значений независимо от того, условие (если не бросить в тонну lambdas), и я не могу видеть это как улучшение по сравнению с тем, с чего мы начали.

1

Я не знаю, почему мы добавляем строки, соответствующие именам функций, но если это общий шаблон, мы можем использовать это. Функции имеют атрибут __name__, и я думаю, что он всегда содержит то, что вы хотите в списке.

Так как насчет:

return [fn.__name__ for fn in (self.taken, self.suggested, foo, bar, baz) if fn()] 

Если я правильно понял проблему правильно, это работает так же хорошо для функций, не являющихся членами, как для функций-членов.

EDIT:

Хорошо, давайте добавим словарь отображения. И разделите имена функций на кортеж или список.

fns_to_check = (self.taken, self.suggested, foo, bar, baz) 

# This holds only the exceptions; if a function isn't in here, 
# we will use the .__name__ attribute. 
fn_name_map = {foo:'alternate', bar:'other'} 

def fn_name(fn): 
    """Return name from exceptions map, or .__name__ if not in map""" 
    return fn_name_map.get(fn, fn.__name__) 

return [fn_name(fn) for fn in fns_to_check if fn()] 

Вы также можете просто использовать словарь ответов hcwhsa. Основное различие здесь заключается в том, что я предлагаю только сопоставление исключений.

+0

Не всегда имена могут быть переоценены плохо разработанными декораторами – alko

0

В другом случае (когда значение будет определяться, но не может быть None - поля модели, Джанго в моем случае), я обнаружил, что просто добавить их и фильтрация работает:

return filter(None, [self.user, self.partner]) 

Если какой-либо из это None, они будут удалены из списка. Это немного более интенсивно, чем просто проверка, но еще довольно простой способ очистки вывода без написания книги.

Смежные вопросы