Python functools——高阶函数

Python functools模块应用于高阶函数,即参数或返回值作为其他函数的函数。

本文代码





以下函数需要Python 3.8,Python3 在线工具

  • cached_property()
  • singledispatchmethod

查看版本:

import sys

print(sys.version)




缓存属性cached_property

计算一次就被缓存

from functools import cached_property

class DataSet:
    def __init__(self, sequence_of_numbers):
        self._data = sequence_of_numbers

    @cached_property
    def stdev(self):
        return statistics.stdev(self._data)

    @cached_property
    def variance(self):
        return statistics.variance(self._data)




函数缓存装饰器lru_cache

斐波那契数列的递推公式如下,在编程中最直接的实现方式是使用递归,如果能将每一步的计算结果缓存下来,那计算效率肯定更高

F ( 1 ) = 1 F ( 2 ) = 1 F ( n ) = F ( n 1 ) + F ( n 2 ) ,    n 3 \begin{array}{l}F(1)=1\\F(2)=1\\F(n)=F(n-1)+F(n-2),\;n\geq3\end{array}

使用functools模块中的lru_cache(),最久未使用(LRU)缓存算法

PS:该算法在计算结果相同时有用,如time()random()之类的函数是没有用的

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


result = [fib(i) for i in range(16)]
print(result)
print(fib.cache_info())  # 查看命中和未命中次数
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
# CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

计算n=16的斐波那契数列的情况下,快250倍。使用了缓存后,n=1000也能轻松计算出来。




自动实现全比较total_ordering

实现其中一个: __lt__(), __le__(), __gt__(), __ge__(),自动实现剩余方法。

注:

  1. 此类需要支持__eq__()
  2. 执行速度更慢
@total_ordering
class Student:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    def __eq__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower()))

    def __lt__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))


a = Student(firstname='a', lastname='bbb')
b = Student(firstname='b', lastname='bbb')
print(a < b)  # True
print(a <= b)  # True
print(a > b)  # False
print(a >= b)  # False
print(a != b)  # True
print(a == b)  # False
print(b == b)  # True




固化参数partial

将部分函数参数固化下来

basetwo = partial(int, base=2)  # basetwo相当于int(x, base=2),将参数base=2固化下来
basetwo('10010')
# 18
print1 = partial(print, end=' ')  # print1相当于print(x, end=' '),将参数end=' '固化下来
print1('Hello', 'World!')
# Hello World! 




用于定义方法的固化参数partialmethod

将部分函数参数固化下来,用作方法定义

class Cell:
    def __init__(self):
        self._alive = False

    @property
    def alive(self):
        return self._alive

    def set_state(self, state):
        self._alive = bool(state)

    set_alive = partialmethod(set_state, True)  # 定义方法
    set_dead = partialmethod(set_state, False)  # 定义方法


c = Cell()
c.set_alive()
print(c.alive)
# True




累积应用reduce

从左到右应用直至算出最终值

print(reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]))  # 相当于((((1+2)+3)+4)+5)
# 15




函数重载singledispatch

根据第一个参数的类型进行重载

@singledispatch
def mul(a, b):
    return a * b


@mul.register(str)
def _(a: str, b: str):
    return int(a) * int(b)


print(mul(1, 2))  # 2
print(mul(1.5, 2.5))  # 3.75
print(mul(1, 1.0))  # 1.0
print(mul('1', '2'))  # 2




用于定义方法的函数重载singledispatchmethod

from functools import singledispatchmethod

class Negator:
    @singledispatchmethod
    def neg(self, arg):
        raise NotImplemented

    @neg.register
    def _(self, arg: int):
        return -arg

    @neg.register
    def _(self, arg: bool):
        return not arg

neg = Negator()
print(neg.neg(5))  # -5
print(neg.neg(True))  # False




更新包装器wraps

自动更新包装器,使其拥有原函数的文档字符串等信息,包括:__module__, __name__, __qualname__, __annotations__, __doc__

不加该装饰器,原函数的信息会消失:

def show_args(f):
#     @wraps(f)
    def wrapper(*args, **kwargs):
        print('调用函数 {} 参数为 {} {}'.format(f.__name__, args, kwargs))
        return f(*args, **kwargs)
    return wrapper


@show_args
def add(a: int, b: int) -> int:
    """加法"""
    return a + b


print(add(5, 1))
print(add.__doc__)
print(add.__name__)
# 调用函数 add 参数为 (5, 1) {}
# 6
# None
# wrapper

加上后保留原函数信息

def show_args(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        print('调用函数 {} 参数为 {} {}'.format(f.__name__, args, kwargs))
        return f(*args, **kwargs)
    return wrapper


@show_args
def add(a: int, b: int) -> int:
    """加法"""
    return a + b


print(add(5, 1))
print(add.__doc__)
print(add.__name__)
# 调用函数 add 参数为 (5, 1) {}
# 6
# 加法
# add




参考文献

  1. functools — 高阶函数和可调用对象上的操作
  2. Python的Functools模块简介
  3. Introduction To Python’s Functools Module

猜你喜欢

转载自blog.csdn.net/lly1122334/article/details/106253473