一、什么是偏函数?

(1)在Python的functools模块众多的功能中,其中有一个就是偏函数,我们称之为 partial function

模块的概念我们下一篇在细讲。

(2)我们都听过偏将军吧,在三国时代的官制中,系将军的辅佐,与裨将军两者都为杂号将军;今天我们要讲的偏函数,其实是函数的辅佐,什么意思呢,我们借助Python的help帮助函数,看一下:

这里我们主要说下红色圈的意思:

partial 一共有三个部分:

(1)第一部分也就是第一个参数,是一个函数,这个函数可以是你定义的,也可以是Python内置函数

(2)第二部分是一个可变参数,*args,比如内置函数max的参数就是一个可变参数,max(1,2,3,4,5)=5

(3)第三部分是一个关键字参数,比如内置函数int的第二个参数就是命名关键字参数,默认base=10,表示int转换时默认是10进制的:

partial函数的作用就是:将所作用的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数的后续参数,原函数有关键字参数的一定要带上关键字,没有的话,按原有参数顺序进行补充。

文字描述显得有些无力,我们下面就开始讲一下,偏函数是怎么用的

二、偏函数的使用

A、偏函数的第二个部分(可变参数),按原有函数的参数顺序进行补充,参数将作用在原函数上,最后偏函数返回一个新函数(类似于,装饰器decorator,对于函数进行二次包装,产生特殊效果;但又不同于装饰器,偏函数产生了一个新函数,而装饰器,可改变被装饰函数的函数入口地址也可以不影响原函数)

案例:我们定义一个sum函数,参数为*args可变,计算这些可变参数的和。

扩展:我们想要对sum函数求和后的结果,再加上10加上20甚至加更多,得到一个新的结果

实现:我们分别用decorator和partial来实现,对比一下二者的区别

(一)装饰器decorator 实现

我们上一篇,刚刚学过decorator,所以这里,我们直接看demo,应该会觉得很容易上手和理解:

test.py

# /usr/bin/env Python3
# -*- encoding:UTF-8 -*- from functools import wraps def sum_add(*args1): #我们要给我们的装饰器decorator,带上参数
def decorator(func):
@wraps(func) #加上这句,原函数func被decorator作用后,函数性质不变
def my_sum(*args2): #注意,参数要和原函数保持一致,真正实行扩展功能的是外层的装饰器
my_s = 0
for n in args1:
my_s = my_s +n #这个是我们新加的求和结果
return func(*args2) + my_s #这个,我们在原求和函数的结果上再加上s,并返回这个值
return my_sum #返回my_sum函数,该函数扩展原函数的功能
return decorator #返回我们的装饰器 @sum_add(10,20) #启用装饰器 对sum函数进行功能扩展
def sum(*args):
s = 0
for n in args:
s = s+n
return s
print(sum(1,2,3,4,5))
print(sum.__name__)

sum(1,2,3,4,5)返回的结果绝不是15,这样就失去了装饰器存在的意义,当然,这里,我们知道,sum最后返回的值应该是10+20+15 = 45,这样一来,我们的decorator就实现了我们想要的扩展功能,最后,发现,原函数sum的name属性,仍然是sum,说明,这种装饰扩展功能,不影响我们的原函数:

(二)偏函数 partial function 实现

这才是我们本篇的重点,准备好了,我们就开始:

我们先来看下普通函数,我们是怎么来实现

A:普通函数可变参数顺序执行

# /usr/bin/env Python3
# -*- encoding:UTF-8 -*- def sum(*args):
s = 0
for n in args:
s = s + n
return s
print(sum(10,20)+sum(1,2,3,4,5))

我们如果想实现+10+20的效果,必须写两遍sum,这样写,显然是最易懂的,但是,却显得很邋遢不专业,我们看下结果:

B:普通函数可变参数加关键字参数组合

针对上面的A过程,我们改下代码,使我们的代码看起来稍显复杂,但是略显专业:

# /usr/bin/env Python3
# -*- encoding:UTF-8 -*- def sum(*args,**others):
s = 0
for n in args:
s = s + n
s1 = 0
for k in others:
s1 = s1 + others[k] #我们还要算一下,关键字参数里蕴藏的求和结果,k是dict中的关键字key
return s+s1 #最终,我们实现扩展功能,顺序参数和关键字参数结果相加 D= {'value1':10,'value2':20}
print(sum(1,2,3,4,5,**D))

代码看起来,是显得专业了,但是感觉冗余,没必要,复杂不是我们Python的风格,我们看下B的结果:

C:偏函数可变参数顺序填充一步到位

上面A和B我们都说过了,这两种方式都不好,显然,这么简单的事情,我们不必麻烦decorator了,那我们还有办法没?有,Python,给我们提供了偏函数,来吧,主角登场:

提示:两种使用partial功能方式

(1)import functools -->functools.partial(func,*args)
(2)from functools import partial -->partial(func,*args)

我们这里选第二种,我们看下demo:

# /usr/bin/env Python3
# -*- encoding:UTF-8 -*-
from functools import partial def sum(*args):
s = 0
for n in args:
s = s + n
return s sum_add_10 = partial(sum,10) #10 作用在sum第一个参数的位置
sum_add_10_20 = partial(sum,10,20) #10 20 分别作用在sum第一个和第二个参数的位置
print('A____________我们看下原函数sum的函数地址入口:')
print(sum)
print('B______我们看下partial函数返回函数的地址入口:')
print(partial(sum,10))
print(sum_add_10(1,2,3,4,5)) # --> 10 + 1 + 2 + 3 + 4 + 5 = 25
print(sum_add_10_20(1,2,3,4,5)) # --> 10 + 20 + 1 + 2 + 3 + 4 + 5 = 45

上面,可以看出,我们针对sum函数的求和结果,再加上10,或者加10加20,甚至加更多,都是可以通过偏函数来实现的,注意偏函数的第二部分,参数是可变的,是按顺序走的,因此,偏函数产生的新函数,sum_add_10 实际上等同于sum(10,*args):

通过几个例子,我们最终发现,还是偏函数比较方便,一行代码就搞定了,而且新定义的函数,可以根据函数名很容易知道,这个函数扩展的原函数是哪个,实现的效果是什么:

B、偏函数的第三个部分(关键字参数),按原有函数的关键字参数进行填补,参数将作用在原函数上,最后偏函数返回一个新函数

案例:我们定义一个mod求余函数,两个参数,一个是被除数,一个是除数,除数我们这里用命名关键字参数表示,默认值2

扩展:我们的除数不固定,可以是对2就行求余,也可以对3,对4,总之我们需要指定除数的值

返回结果: True 或 False

实现:原函数实现和partial函数实现

demo如下:

# /usr/bin/env Python3
# -*- encoding:UTF-8 -*-
import functools
def mod(m,*,key=2):
return m % key == 0
mod_to_2 = functools.partial(mod,key=2)
print('A__3___使用原函数的默认关键字参数对2进行求余:')
print(mod(3)) #对2进行求余-- 原函数 使用默认参数
print('B__3___使用偏函数对2进行求余:')
print(mod_to_2(3)) #对2进行求余-- 新函数 --偏函数产生
mod_to_5 = functools.partial(mod,key=5)
print('C__25___使用原函数的关键字参数对5进行求余:')
print(mod(25,key=5)) #对5进行求余 -- 原函数
print('D__25___使用偏函数对5进行求余:')
print(mod_to_5(25)) #对5进行求余 -- 新函数--偏函数产生

我们看下结果:

我们发现,实际上,偏函数的作用,其实和原函数差不多,只不过,我们要多次调用原函数的时候,有些参数,我们需要多次手动的去提供值,比如上述的对5进行求余,如果我们想知道,15,45,30这些数是否能够被5整除,那么,我们用原函数的话,就需要写三次,key=5,然而,我们用偏函数的话,只需要重复调用新产生的函数mod_to_5(15
or 45 or 30)即可,至于除数5,偏函数已经为我们设定了,因此:

当函数的参数个数太多,需要简化时,使用 functools.partial 可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。当然,decorator也可以实现,如果,我们不嫌麻烦的话。

结束语:

一种方案行不通的话,我们就换另一种方案,如果两种方案都行得通的话,我们确保那个最简单高效的方案,这样一来,最后受益的将是我们自己。


*{
margin-left: -8px;
}
-->

python中偏函数的应用的更多相关文章

  1. python中偏函数

    当一个函数有很多参数时,调用者就需要提供多个参数.如果减少参数个数,就可以简化调用者的负担. 比如,int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换: >& ...

  2. python 中偏函数 partial 的使用

    函数的partial应用 函数在执行时,要带上所有必要的参数进行调用.但是,有时参数可以在函数被调用之前提前获知.这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用. 例 ...

  3. Python中的偏函数

    偏函数是从Python2.5引入的一个概念,通过functools模块被用户调用. 偏函数是将所要承载的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数后续的 ...

  4. python基础——偏函数

    python基础——偏函数 Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function).要注意,这里的偏函数和数学意义上的偏函数不一样. 在介绍函 ...

  5. Python之偏函数

    学前知识储备: 函数在Python是第一类对象 (Python中一切皆对象). 第一类对象的特性: ----1.可以被引用 ----2.可以当做参数传入 ----3.可以当做函数返回值 ----4.可 ...

  6. Python 中的闭包和自由变量

    1.定义 在函数内部再定义一个函数,并且这个函数用到了外部函数的变量(LEGB),最后返回新建函数的函数名索引,那么将这样的能够访问其定义时所在的作用域的函数以及用到的一些变量称之为闭包.被引用的非全 ...

  7. [转]Python中的str与unicode处理方法

    早上被python的编码搞得抓耳挠腮,在搜资料的时候感觉这篇博文很不错,所以收藏在此. python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自 ...

  8. python中的Ellipsis

    ...在python中居然是个常量 print(...) # Ellipsis 看别人怎么装逼 https://www.keakon.net/2014/12/05/Python%E8%A3%85%E9 ...

  9. python中的默认参数

    https://eastlakeside.gitbooks.io/interpy-zh/content/Mutation/ 看下面的代码 def add_to(num, target=[]): tar ...

随机推荐

  1. 封装CoreGraphics的API简化绘图操作

    封装CoreGraphics的API简化绘图操作 效果 说明 1. 将CoreGraphics的API接口抽象为对象,让绘图变得简单易懂 2. 简化常用的绘制操作 3. 源码长期更新 源码 https ...

  2. October 04th 2017 Week 40th Wednesday

    We teach people how to remember, we never teach them how to grow. 我们教会人们如何记忆,却从来不教他们如何成长. Without pr ...

  3. 获取URL网页信息

    static string GetHtml(string url) {string strHTML = ""; WebClient myWebClient = new WebCli ...

  4. Maven实战(八)pom.xml简介

    目录 pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件.开发者需要遵循的规则.缺陷管理系统.组织和licenses.项目的url.项目的依赖 ...

  5. python subprocess 和 multiprocess选择以及我遇到的坑

    The subprocess option: subprocess is 用来执行其他的可执行程序的,即执行外部命令. 他是os.fork() 和 os.execve() 的封装. 他启动的进程不会把 ...

  6. Android进阶笔记18:Android 获取Button的高度、宽度、坐标值

    1. 问题 如何获取一个控件的长和高,相信很多朋友第一眼看见这个问题都会觉得很简单,直接在onCreate里面调用getWidth.getMeasuredWidth不就可以获得了吗,但是,事实上是并没 ...

  7. django 取model字段的verbose_name值

    Django 模型中的verbose_name我们常常可能需要使用.比如将数据库里面的数据导出成csv文件,那么csv文件的表头的名字可以通过取每个字段的verbose_name来获取,数据可以通过q ...

  8. Golang - 数据库操作

    1. 下载安装包 go get github.com/Go-SQL-Driver/MySQL go install github.com/Go-SQL-Driver/MySQL 2. 连接池 This ...

  9. ASP.NET web api 跨域请求

    1.学习文章:AJAX 跨域请求 - JSONP获取JSON数据 1.asp.net代码 参考文章:http://www.sxt.cn/info-2790-u-756.html (1).增加CorsH ...

  10. Hive学习之路 (九)Hive的内置函数

    数学函数 Return Type Name (Signature) Description DOUBLE round(DOUBLE a) Returns the rounded BIGINT valu ...