python学习 -偏函数

1、什么是偏函数?python

 

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

         模块的概念咱们下一篇在细讲。函数

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

 

这里咱们主要说下红色圈的意思:3d

partial 一共有三个部分:code

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

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

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

 

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

 

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

 

2、偏函数的使用

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

 

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

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

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

 

(一)装饰器 decorator 实现

咱们上一篇,刚刚学过decorator,因此这里,咱们直接看demo,应该会以为很容易上手和理解:

test.py

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3.  
  4. from functools import wraps

  5.  
  6. def sum_add(*args1): #咱们要给咱们的装饰器decorator,带上参数

  7. def decorator(func):

  8. @wraps(func) #加上这句,原函数func被decorator做用后,函数性质不变

  9. def my_sum(*args2): #注意,参数要和原函数保持一致,真正实行扩展功能的是外层的装饰器

  10. my_s = 0

  11. for n in args1:

  12. my_s = my_s +n #这个是咱们新加的求和结果

  13. return func(*args2) + my_s #这个,咱们在原求和函数的结果上再加上s,并返回这个值

  14. return my_sum #返回my_sum函数,该函数扩展原函数的功能

  15. return decorator #返回咱们的装饰器

  16.  
  17. @sum_add(10,20) #启用装饰器 对sum函数进行功能扩展

  18. def sum(*args):

  19. s = 0

  20. for n in args:

  21. s = s+n

  22. return s

  23. print(sum(1,2,3,4,5))

  24. print(sum.__name__)

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

 

(二)偏函数 partial function 实现

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

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

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

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3.  
  4. def sum(*args):

  5. s = 0

  6. for n in args:

  7. s = s + n

  8. return s

  9. print(sum(10,20)+sum(1,2,3,4,5))


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

 

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

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

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3.  
  4. def sum(*args,**others):

  5. s = 0

  6. for n in args:

  7. s = s + n

  8. s1 = 0

  9. for k in others:

  10. s1 = s1 + others[k] #咱们还要算一下,关键字参数里蕴藏的求和结果,k是dict中的关键字key

  11. return s+s1 #最终,咱们实现扩展功能,顺序参数和关键字参数结果相加

  12.  
  13. D= {'value1':10,'value2':20}

  14. 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:

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3. from functools import partial

  4.  
  5. def sum(*args):

  6. s = 0

  7. for n in args:

  8. s = s + n

  9. return s

  10.  
  11. sum_add_10 = partial(sum,10) #10 做用在sum第一个参数的位置

  12. sum_add_10_20 = partial(sum,10,20) #10 20 分别做用在sum第一个和第二个参数的位置

  13. print('A____________咱们看下原函数sum的函数地址入口:')

  14. print(sum)

  15. print('B______咱们看下partial函数返回函数的地址入口:')

  16. print(partial(sum,10))

  17. print(sum_add_10(1,2,3,4,5)) # --> 10 + 1 + 2 + 3 + 4 + 5 = 25

  18. 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以下:

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3. import functools

  4. def mod(m,*,key=2):

  5. return m % key == 0

  6. mod_to_2 = functools.partial(mod,key=2)

  7. print('A__3___使用原函数的默认关键字参数对2进行求余:')

  8. print(mod(3)) #对2进行求余-- 原函数 使用默认参数

  9. print('B__3___使用偏函数对2进行求余:')

  10. print(mod_to_2(3)) #对2进行求余-- 新函数 --偏函数产生

  11. mod_to_5 = functools.partial(mod,key=5)

  12. print('C__25___使用原函数的关键字参数对5进行求余:')

  13. print(mod(25,key=5)) #对5进行求余 -- 原函数

  14. print('D__25___使用偏函数对5进行求余:')

  15. print(mod_to_5(25)) #对5进行求余 -- 新函数--偏函数产生


咱们看下结果:

 

咱们发现,实际上,偏函数的做用,其实和原函数差很少,只不过,咱们要屡次调用原函数的时候,有些参数,咱们须要屡次手动的去提供值,好比上述的对5进行求余,若是咱们想知道,15,45,30这些数是否可以被5整除,那么,咱们用原函数的话,就须要写三次,key=5,然而,咱们用偏函数的话,只须要重复调用新产生的函数mo

1、什么是偏函数?

 

(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()函数的后续参数,原函数有关键字参数的必定要带上关键字,没有的话,按原有参数顺序进行补充。

 

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

 

2、偏函数的使用

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

 

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

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

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

 

(一)装饰器 decorator 实现

咱们上一篇,刚刚学过decorator,因此这里,咱们直接看demo,应该会以为很容易上手和理解:

test.py

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3.  
  4. from functools import wraps

  5.  
  6. def sum_add(*args1): #咱们要给咱们的装饰器decorator,带上参数

  7. def decorator(func):

  8. @wraps(func) #加上这句,原函数func被decorator做用后,函数性质不变

  9. def my_sum(*args2): #注意,参数要和原函数保持一致,真正实行扩展功能的是外层的装饰器

  10. my_s = 0

  11. for n in args1:

  12. my_s = my_s +n #这个是咱们新加的求和结果

  13. return func(*args2) + my_s #这个,咱们在原求和函数的结果上再加上s,并返回这个值

  14. return my_sum #返回my_sum函数,该函数扩展原函数的功能

  15. return decorator #返回咱们的装饰器

  16.  
  17. @sum_add(10,20) #启用装饰器 对sum函数进行功能扩展

  18. def sum(*args):

  19. s = 0

  20. for n in args:

  21. s = s+n

  22. return s

  23. print(sum(1,2,3,4,5))

  24. print(sum.__name__)

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

 

(二)偏函数 partial function 实现

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

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

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

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3.  
  4. def sum(*args):

  5. s = 0

  6. for n in args:

  7. s = s + n

  8. return s

  9. print(sum(10,20)+sum(1,2,3,4,5))


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

 

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

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

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3.  
  4. def sum(*args,**others):

  5. s = 0

  6. for n in args:

  7. s = s + n

  8. s1 = 0

  9. for k in others:

  10. s1 = s1 + others[k] #咱们还要算一下,关键字参数里蕴藏的求和结果,k是dict中的关键字key

  11. return s+s1 #最终,咱们实现扩展功能,顺序参数和关键字参数结果相加

  12.  
  13. D= {'value1':10,'value2':20}

  14. 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:

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3. from functools import partial

  4.  
  5. def sum(*args):

  6. s = 0

  7. for n in args:

  8. s = s + n

  9. return s

  10.  
  11. sum_add_10 = partial(sum,10) #10 做用在sum第一个参数的位置

  12. sum_add_10_20 = partial(sum,10,20) #10 20 分别做用在sum第一个和第二个参数的位置

  13. print('A____________咱们看下原函数sum的函数地址入口:')

  14. print(sum)

  15. print('B______咱们看下partial函数返回函数的地址入口:')

  16. print(partial(sum,10))

  17. print(sum_add_10(1,2,3,4,5)) # --> 10 + 1 + 2 + 3 + 4 + 5 = 25

  18. 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以下:

 

 
  1. # /usr/bin/env Python3

  2. # -*- encoding:UTF-8 -*-

  3. import functools

  4. def mod(m,*,key=2):

  5. return m % key == 0

  6. mod_to_2 = functools.partial(mod,key=2)

  7. print('A__3___使用原函数的默认关键字参数对2进行求余:')

  8. print(mod(3)) #对2进行求余-- 原函数 使用默认参数

  9. print('B__3___使用偏函数对2进行求余:')

  10. print(mod_to_2(3)) #对2进行求余-- 新函数 --偏函数产生

  11. mod_to_5 = functools.partial(mod,key=5)

  12. print('C__25___使用原函数的关键字参数对5进行求余:')

  13. print(mod(25,key=5)) #对5进行求余 -- 原函数

  14. print('D__25___使用偏函数对5进行求余:')

  15. 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也能够实现,若是,咱们不嫌麻烦的话。

 

结束语:

一种方案行不通的话,咱们就换另外一种方案,若是两种方案都行得通的话,咱们确保那个最简单高效的方案,这样一来,最后受益的将是咱们本身。

d_to_5(15 or 45 or 30)便可,至于除数5,偏函数已经为咱们设定了,所以:

当函数的参数个数太多,须要简化时,使用 functools.partial 能够建立一个新的函数,这个新函数能够固定住原函数的部分参数,从而在调用时更简单。固然,decorator也能够实现,若是,咱们不嫌麻烦的话。

 

结束语:

一种方案行不通的话,咱们就换另外一种方案,若是两种方案都行得通的话,咱们确保那个最简单高效的方案,这样一来,最后受益的将是咱们本身。

相关文章
相关标签/搜索