Как стать автором
Обновить

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

Может изменить заголовок на «Не---практичный ...»
Будет ещё круче!
Чтобы с самого начала было всем и совсем понятно, что правила русского языка к этому опусу не имеют никакого отношения!
А по мне, так просто замечательно! Не знаю, вон, Думу на лампочке или пианино аплодируют, а однострочнику в Питоне — нет, что ли? Тоже имеет право на полчаса чьего-то времени.

P.S. От "читаймо", конечно, чуть глаз не лопнул, но я их просто руками придерживал, пока не долистал до однострочника, ничего страшного.
Я то ожидал сложность в ограничении 4 строки будет в соблюдении PEP8: E501

В питоне метод .get у dict возвращает значение, а если ключа не существует - None.

Так же есть or, которая возвращает 1ое, если оно приводится к True, иначе 2ое.

Таким обзразом None or default_value вернёт default_value.

Это очень полезно для работы со словарями, ТК вы можете использовать такую связку

data[key] = data.get(key) or func(args)

return data[key]

Превратить это в функцию, или если вам угодно, лямбда функцию, не составит труда, однако читаемость и лаконичность кода значительно повышаются.

Если вам очень важно число обращений к data, лучше использовать if key in data.

data[key] = data.get(key) or func(args)

Тут еще надо учитывать, что в словаре могут быть «пустые» значения ('', 0, False, [] и т.д.), тогда этот вариант будет делать не совсем то, что требуется

Согласен, не учел. Тогда это можно сделать так:

data[key] = func(args) if data.get(key) is None else data[key]

Что уже не так лаконично (с ? : выглядело бы лучше, но это уже другой вопрос), но все ещё сокращает код.

None тоже можно поместить в словарь… Если писать код не в одну строку, то всегда лучше обрабатывать KeyError.

Вообще-то dict.get принимает два параметра. Второй — значение по умолчанию.
Так что можно написать data[key] = data.get(key, func(args))

В этом случае func будет вызываться при каждом вызове get, а в случае or — только при False в первом условии
Сдается мне, что func(args) в этом случае вызовется до вызова метода get, поэтому «вообще то» тут не аргумент
data[key] = data.get(key, func(args))

Ленивого исполнения аргументов в Python как‐то не завезли. Вы в этом варианте всегда вызываете func(args).

мне кажется такие «размышления» нужно публиковать, вопрос академический, но полезный для знакомства
key = f"{func.__name__}{args}" 
# проверяем кэшировли дунную функцию с аргументами 
if args in data:
    return data.get(key)

А разве не if key in data? Разве можно по части ключа в словаре что-то найти?

В рамках академического изыскания хорошо еще почитать про stdlib: @functools.cache.

так же в голову сразу пришло.

Вот моя версия, надеюсь, вы это вынесите:

def cached(func, data={}, _s=object()): return lambda *args: ((data.__setitem__(f"{func.__name__}({args})", func(*args)), data[f"{func.__name__}({args})"])[1]) if data.get(f"{func.__name__}({args})", _s) is _s else data[f"{func.__name__}({args})"]

Зачем здесь всё?

  1. data - собственно кеш, так потому что в 1 строку

  2. _s как sentinel тоже самое, но чтобы различать None после вызова и отсутствие результата

Можно было бы впихнуть в параметры лямбду по получению ключа, но пока зачем.

(data.__setitem__("<>", func(*args)), data["<>")[1]

Это создание кортежа, в котором происходит запись результата функции и тут же рядом достается, потому что не везде есть walrus operator и вообще я его не очень люблю, зато __setitem__ является обычной функцией и возвращает ничего, то есть является валиднвм выражением в отличие от data["<>"] = func(*args).

def cache(func): return lambda *a, **k: func.__dict__.setdefault(f'{a}:{k}', f'{a}:{k}' in func.__dict__ or func(*a, **k)) or func.__dict__[f'{a}:{k}']

3 действия


  1. вызываем функцию только если элемента нет в кеше
    f'{a}:{k}' in func.__dict__ or func(*a, **k))
  2. записываем новое значение, если его нет в кеше
    func.__dict__.setdefault(f'{a}:{k}', ...
  3. возвращаем значение из кеша
    or func.__dict__[f'{a}:{k}']
Чувак, который изучает python: «да кто это такие ваши декораторы и лямбды». Вот, держи, чисто академический пример:
image
Такие штуки интересно поделать парой. Спасибо за пример :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории