2013-05-30 5 views
1

Я пытаюсь исключить случаи на понимание, которые возвращают None. Следующее выполняет его, но приводит к вызову функции дважды !!!Как исключить случаи из соображений

>>> def func(x): 
...  if x>10: 
...   return None 
...  else: 
...   return x*2 
...   
>>> result1=[func(x) for x in l if func(x) is not None] 
>>> result1 
[4, 8, 14, 6] 

Каким будет выход?

ответ

4
result1[:] = [x for x in map(func, l) if x is not None] 

Об использовании 2.x Python itertools.imap

Примечание:filter(None, map(func, l)) обычно работать, но это будет также удалить 0 (так как он считается пустым)

+0

спасибо - действительно ли imap дает какое-либо дополнительное преимущество перед картой? – IUnknown

+0

@IUnknown Он возвращает итератор вместо списка. Это более эффективно для огромных наборов данных, для небольших списков вы не увидите большой разницы. – jamylak

+0

Просто еще одна проблема - как я могу назвать карту для функции, которая принимает несколько дополнительных параметров - def func (x, множитель). – IUnknown

2

Что об этом коде:

print([x*2 for x in l if x <= 10]) 

Редактировать

Обычно она может принимать форму:

print([process(x) for x in l if is_valid(x)] 
+0

+1 имеет смысл просто сделать это – jamylak

+0

Правда - но функция у меня намного сложнее и на самом деле не зависит от входа. – IUnknown

+0

В этом случае вы можете отделить функции. Один проверяет, действителен ли элемент для обработки, а второй обрабатывает его. – StKiller

1
def func(x): 
    if x>10: 
     return None 
    else: 
     return x*2 

lst = [2, 4, 12, 7, 30, 3] 

# original 
result0 = [func(x) for x in lst if func(x) is not None] 

# map... on Python 2.x, use itertools.imap() 
result1 = [x for x in map(func, lst) if x is not None] 
assert result1 == result0 

# generator expression 
result2 = [x for x in (func(y) for y in lst) if x is not None] 
assert result2 == result0 

# rewrite function as a generator function 
def func_gen(iterable): 
    for x in iterable: 
     if x <= 10: 
      yield x*2 

# no need to filter; filtering happens in generator function 
result3 = list(func_gen(lst)) 
assert result3 == result0 


# build a filtering generator out of parts 
def fn_x2(x): 
    return x * 2 

def filter_leq10(x): 
    return x <= 10 

def make_filtering_gen_func(fn, flt, name="anonymous"): 
    def anonymous(iterable): 
     for x in iterable: 
      if flt(x): 
       yield fn(x) 
    anonymous.__name__ = name 
    return anonymous 

func_gen1 = make_filtering_gen_func(fn_x2, filter_leq10) 
result4 = list(func_gen1(lst)) 
assert result4 == result0 

Комментарии.

@jamylak уже показал вам, как его решить map() или itertools.imap(). Но по какой-то причине он/она показал переписывание существующего списка, используя нарезку. Я не вижу причин для этого, поэтому я показал его с привязкой к имени переменной.

Наиболее часто рекомендуемая альтернатива map() является выражением генератора, поэтому я показал, как использовать ее внутри понимания списка.

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

И, наконец, функциональный способ создания фильтрующего генератора из деталей! Вы можете передать любую функцию, которая принимает один аргумент (и помните, что вы можете использовать functools.partial(), чтобы связать другие аргументы и получить объект функции, который просто принимает один аргумент), плюс передать функцию фильтра, которая выбирает значения. Он создает объект функции и возвращает его, который автоматически обрабатывает «шаблонный» для вас, добавляя цикл for, тест if для фильтрации, а затем yield с результатами.

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