python使用高阶函数实现_Python 构建高阶函数

Python 构建高阶函数,可以通过创建Callable类对象来定义高阶函数。与编写生成器函数的思路类似,编写可调用对象是为了使用Python语句。除了能使用语句外,还可以在创建高阶函数时进行静态配置。

通过class声明定义Callable类对象,实际上定义了一个以函数为返回值的函数。通常可以使用可调用对象把两个函数组合起来,形成一个复杂函数。

如下面的类所示:

这个类用于创建空值敏感的新函数。创建这个类的实例时需要提供一个函数(some_func)作为参数,对该函数的限制条件由Callable[[Any], Any]定义,即输入单一值并返回单一值。返回结果是可调用的,并接收一个可选参数。__call__()方法处理参数为None的情况,这个方法将返回结果类型定义为Callable[[Optional[Any]], Optional[Any]]。

对表达式NullAware(math.log)求值,创建出一个作用于参数的新函数。__init__方法将用户定义的函数保存在结果对象中,该对象是个包含数据处理逻辑的函数。

通常会为生成的新函数指定一个名称,以便后续使用,如下所示:

这里将新创建的函数赋给变量null_log_scale,接下来就可以在新的上下文中使用该函数了,如下所示:

或者像下面这样,把创建和使用函数写在同一个表达式中:

对NullAware(math.log)求值的返回结果是一个匿名函数,该函数在map()函数中用于处理可迭代对象some_data。

上面例子中的__call__()方法完全基于表达式求值,是一种简洁易用的基于底层组件函数创建复合函数的方法。当使用标量函数时,只需考虑很少几个设计约束就可以了,而当涉及可迭代集合时,就需要仔细斟酌了。

确保正确的函数式设计

使用无状态的函数式Python代码时,要注意使用对象,因为对象是有状态的。实际上,面向对象编程旨在把状态变化封装到类定义中。这样在使用Python类定义处理集合时,你会发现函数式编程和命令式编程背道而驰。

使用可调用对象创建复合函数,让我们能以相对简单的语法使用这些复合函数。在使用可迭代映射或者归约时,需要注意引入有状态对象的原因及方式。

回到之前的sum_filter_f()复合函数。基于Callable类定义的实现如下:

这个类的每个对象只能有两个属性,以降低后续把该函数当成有状态对象使用的可能性。这种限制并不能完全杜绝对返回结果对象的修改,但将对象属性限制为两个,使得添加其他属性将引发异常。

初始化方法__init__()为对象实例加载了两个函数:filter和func。__call__()方法的返回值是一个生成器表达式,这个生成器表达式又使用了前两个函数。其中self.filter()方法用于对集合元素进行取舍,self.function()函数用于转换通过了filter()函数检验的元素。

类的实例是包含两个策略函数的函数。创建类的实例如下所示:

该函数的功能是计算序列中非None元素的个数。它使用了两个匿名函数:一个过滤出序列中的非None元素,另一个将所有非None元素转换为1。

总的说来,这个count_not_none()函数与其他Python函数一样,使用方法比前面的sum_filter_f()函数简单一些。

如下所示使用count_not_none()函数:

如下所示使用sum_filter_f()函数:

可以看出,基于一个可调用对象的count_not_none()函数比普通函数的参数要少,所以使用起来相对简单。但它定义函数行为的代码分散在两处(可调用类中的定义,以及使用函数时指定的参数),从这个角度看,这种方式似乎不够清晰明了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值