Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Решение (лучше всего, если у вас есть повторяющееся значение x) было бы memoize функции f, т. е. создать функцию-оболочку, которая сохраняет аргумент, по которому вызывается функция, и сохраняет его, а не возвращает его, если тот же .
действительно простая реализация заключается в следующем:
storage = {}
def memoized(value):
if value not in storage:
storage[value] = f(value)
return storage[value]
[memoized(x) for x in l if memoized(x)]
, а затем использовать эту функцию в понимании списка. Этот подход справедлив в двух условиях: один теоретический и один практический. Первый заключается в том, что функция f должна быть детерминированной, т. Е. Возвращает те же результаты при одном и том же входе, а другая в том, что объект x можно использовать в качестве словарных клавиш. Если первый из них недействителен, вы должны перепроверить f каждый раз по определению, а если второй не удастся, можно использовать несколько более надежные подходы.
Вы можете найти много реализаций memoization net, и я думаю, что в новых версиях python есть что-то, что включено в них.
На боковой ноте никогда не используйте маленький L в качестве имени переменной, это плохая привычка, поскольку ее можно смутить с i или 1 на некоторых терминалах.
EDIT:
, как прокомментировано, возможным решением с использованием генераторов (чтобы избежать создания бесполезных дублированных времен) было бы это выражение:
[g(x, fx) for x, fx in ((x,f(x)) for x in l) if fx]
Вам нужно весить свой выбор, учитывая вычислительную стоимость f, количество дубликатов в исходном списке и память при вашем расположении. Воспоминание делает компромисс между космическими скоростями, что означает, что он сохраняет следы каждого результата, сохраняя его, поэтому, если у вас есть огромные списки, это может стать дорогостоящим на фронте памяти.
Как показали предыдущие ответы, вы можете использовать двойное понимание или использовать memoization. Для проблем с разумным размером это вопрос вкуса (и я согласен с тем, что memoization выглядит более чистым, поскольку он скрывает оптимизацию). Но если вы изучаете очень большой список, есть огромная разница: Memoization будет хранить каждое вычисленное значение и может быстро сдуть вашу память. Двойное понимание с генератором (круглые парнеты, а не квадратные скобки) сохраняет только то, что вы хотите сохранить.
Чтобы перейти к вашей реальной проблеме:
[g(x, f(x)) for x in series if f(x)]
Чтобы вычислить окончательный вам нужны оба x
и f(x)
. Нет проблем, передайте их следующим образом:
[g(x, y) for (x, y) in ( (x, f(x)) for x in series ) if y ]
Опять же: это должно быть использование генератора (раунд parens), а не понимание списка (квадратные скобки). В противном случае вы выведете весь список, прежде чем приступать к фильтрации результатов. Это версия для понимания списка:
[g(x, y) for (x, y) in [ (x, f(x)) for x in series ] if y ] # DO NOT USE THIS
[g(x, y) for x in series for y in [f(x)] if y]
разным в занятии памяти? когда запомненный список будет очищен (зависит от того, где определена запоминаемая функция)?
– user110954
14 September 2017 в 17:41
Как насчет определения:
def truths(L):
"""Return the elements of L that test true"""
return [x for x in L if x]
Так, например,
> [wife.children for wife in henry8.wives]
[[Mary1], [Elizabeth1], [Edward6], [], [], []]
> truths(wife.children for wife in henry8.wives)
[[Mary1], [Elizabeth1], [Edward6]]
Вот мое решение:
filter(None, [f(x) for x in l])
filter
- И я обычно предпочитаю filter(bool,...)
- filter(None,...)
. Делают то же самое, но я считаю, что первое было более явным. например Я думаю, что это будет лучше, чем filter(bool,(f(x) for x in l))
– mgilson
4 April 2013 в 15:20
Вы можете использовать memoization . Это метод, который используется для того, чтобы избежать выполнения одного и того же вычисления дважды, сохраняя где-то результат для каждого рассчитанного значения. Я видел, что уже есть ответ, который использует memoization, но я хотел бы предложить общую реализацию, используя декораторы python:
def memoize(func):
def wrapper(*args):
if args in wrapper.d:
return wrapper.d[args]
ret_val = func(*args)
wrapper.d[args] = ret_val
return ret_val
wrapper.d = {}
return wrapper
@memoize
def f(x):
...
Теперь f
- это сама memoized версия. С этой реализацией вы можете memoize любую функцию, используя декоратор @memoize
.
Было много ответов на memoizing. Стандартная библиотека Python 3 теперь имеет lru_cache
, который является последним использованным кэшем . Таким образом, вы можете:
from functools import lru_cache
@lru_cache()
def f(x):
# function body here
Таким образом, ваша функция будет вызываться только один раз. Вы также можете указать размер lru_cache
, по умолчанию это 128. Проблема с декораторами memoize, показанная выше, заключается в том, что размер списков может значительно увеличиться.
lru_cache
1, так как я только хочу повторно использовать последнее используемое значение?
– Stefan
10 September 2014 в 12:26
Использовать map()
!!
comp = [x for x in map(f, l) if x]
f
- это функция f(X)
, l
- список
map()
вернет результат f(x)
для каждого x в списке.
Вы должны использовать декоратор memoize. Вот интересная ссылка .
Использование memoization из ссылки и вашего «кода»:
def memoize(f):
""" Memoization decorator for functions taking one or more arguments. """
class memodict(dict):
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return memodict(f)
@memoize
def f(x):
# your code
[f(x) for x in l if f(x)]
f.f(...)
, он сохраняет состояние на основе каждой функции (в отличие от глобальной), он использует dict.__missing__
, что так полезно. У тебя есть моя возвышенность.
– mgilson
4 April 2013 в 15:23
Нет. Для этого нет ( clean ). Нет ничего плохого в хорошем старомодном цикле:
output = []
for x in l:
result = f(x)
if result:
output.append(result)
Если вы считаете, что трудно читать, вы всегда можете обернуть его в функцию.
[y for y in [f(x) for x in l] if y]
Для вашей обновленной проблемы это может быть полезно:
[g(x,y) for x in l for y in [f(x)] if y]
storage
, что означает, что вам нужно сброситьstorage
, прежде чем вы вызовете это на новом наборе данных. Все, чтобы вы могли легко использовать понимание списка. ИМХО, этого не стоит. Просто используйте цикл. – mgilson 4 April 2013 в 15:05