вторник, 2 июня 2020 г.

ЛМНты Python, 61 - 65

>>> Декоратор lru_cache

Еще один полезный декоратор из модуля functools стандартной библиотеки Python – это lru_cache(maxsize=128, typed=False). Этот декоратор запоминает до maxsize последних результатов, возвращаемых декорированной функцией для различных аргументов и, в случае повторного обращения к функции с теми же аргументами, возвращает результат из кэша вместо того, чтобы вызывать функцию.

Воспользуемся им, чтобы кэшировать значения чисел Фибоначчи, рассчитанные функцией fibc.

>>> def fib(n):
...     if n < 2:
...         return n
...     return fib(n-1) + fib(n-2)
...
>>> fib(35) # несколько секунд...
9227465
>>>
>>> from functools import lru_cache
>>>
>>> @lru_cache(maxsize=36)
... def fibc(n):
...     if n < 2:
...         return n
...     return fibc(n-1) + fibc(n-2)
...
>>> fibc(35) # гораздо быстрее
9227465

Декоратор lru_cache также снабжает декорированную функцию методом cache_info (ведь функции – тоже объекты!), который покажет статистику использования кэша:

>>> fibc.cache_info()
CacheInfo(hits=33, misses=36, maxsize=36, currsize=36)

Подробнее о декораторе lru_cache см. документацию Python.

>>> Декоратор с параметрами

Декоратор с параметрами – это функция с параметрами, возвращающая обычный декоратор с единственным параметром-функцией:

>>> def deco_abc(a, b, c):
...     def deco(fun):
...         def f(*args, **kwargs):
...             print(a, b, c)
...             return fun(*args, **kwargs)
...         return f
...     print(a, b, c)
...     return deco
...
>>> @deco_abc(1, 3, 7)
... def hi(name):
...     return 'hi, ' + name
...
1 3 7
>>> hi('Andrei')
1 3 7
'hi, Andrei'

В данном случае декорирование функции hi эквивалентно следующему:

>>> def hi(name):
...     return 'hi, ' + name
...
>>> hi = deco_abc(1, 3, 7)(hi)
1 3 7
>>> hi('Andrei')
1 3 7
'hi, Andrei'

>>> Декоратор может

Итак, декоратор может

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

Дополнительная функциональность добавляется в функцию-обертку (вместо комментариев # сделать что-то еще...):

def deco(fun):
    def f(*args, **kwargs):
        # сделать что-то еще...
        result = fun(*args, **kwargs)
        # сделать что-то еще...
        return result
    return f

А обработка функции выполняется в функции-декораторе (вместо комментария # зарегистрировать функцию...):

def deco(fun):
    # зарегистрировать функцию
    return fun

Если в декоририруемую функцию не нужно добавлять дополнительную функциональность, то декоратор даже не использует функцию-обертку.

>>> Список уникальных значений

Чтобы удалить из списка повторяющиеся значения, нужно превратить его в множество и затем снова в список:

>>> # список с повторяющимися значениями
>>> a = list(2 * 'hello')
>>> a
['h', 'e', 'l', 'l', 'o', 'h', 'e', 'l', 'l', 'o']
>>>
>>> # избавимся от одинаковых элементов
>>> a = list(set(a))
>>> a
['l', 'e', 'h', 'o']

А так можно проверить, что в списке нет повторяющихся значений:

>>> if len(a) == len(set(a)):
...     print('Значения в списке уникальны')
... else:
...     print('Есть повторяющиеся значения')
...
Значения в списке уникальны

>>> Множества могут

Операции над множествами в Python можно выполнять с помощью методов или с помощью операторов (это справедливо не только для множеств):

>>> # объединение
>>> {1, 2, 3} | {3, 4, 5}
{1, 2, 3, 4, 5}
>>> {1, 2, 3}.union({3, 4, 5})
{1, 2, 3, 4, 5}
>>>
>>> # пересечение
>>> {1, 2, 3} & {3, 4, 5}
{3}
>>> {1, 2, 3}.intersection({3, 4, 5})
{3}
>>>
>>> # разность
>>> {1, 2, 3} - {3, 4, 5}
{1, 2}
>>> {1, 2, 3}.difference({3, 4, 5})
{1, 2}
>>>
>>> # симметрическая разность
>>> {1, 2, 3} ^ {3, 4, 5}
{1, 2, 4, 5}
>>> {1, 2, 3}.symmetric_difference({3, 4, 5})
{1, 2, 4, 5}

Комментариев нет:

Отправить комментарий