1. 返回函数:

所谓的返回函数,指的是函数作为返回值。高阶函数除了可以接受函数作为参数外,同样可以接受函数作为结果返回。以下是一个可变参数的求和例子,一般求和函数是如此这般定义的:

 >>> def sum(*args):
... ax =
... for x in args:
... ax += x
... return ax
...

以上函数一旦定义,在调用这个函数的时候,只要传入参数就会立刻执行。但是,如果条件需要不要立刻求和,而是在后面的代码中,根据需要再计算该怎么办?可以不返回求和的结果,而是返回求和的函数!

 >>> def lazy_sum(*args):
... def sum():
... ax =
... for n in args:
... ax = ax + n
... return ax
... return sum
...
>>>
>>> lazy_sum()
<function sum at 0x7f810add16e0>
>>> lazy_sum((,,,,,))
<function sum at 0x7f810add17d0>
>>>
KeyboardInterrupt
>>># 以上是调用lazy_sum()函数的结果返回的不是求和的结果,而是求和函数

但是该如何才能够返回结果呢?演示如下:

 >>> result = lazy_sum(,,,,,,,)
>>> result
<function sum at 0x7f810add17d0>
>>> #其实result现在是一个返回函数,要再调用该函数才可以返回结果
...
>>> result()

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

 >>> result1 = lazy_sum(,,,,,,,,,)
>>> result2 = lazy_sum(,,,,,,,,,)
>>> result1
<function sum at 0x7f810add16e0>
>>> result2
<function sum at 0x7f810add1848>
>>> result1 == result2
False
>>>

如上代码显示:0x7f810add16e0是不等于0x7f810add1848的,因此比较结果为FALSE。但是,什么是“闭包”呢?记得在离散数学里面学习过闭包的知识,关系闭包.......。

2. 闭包:

  注意到返回函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了result()才执行。我们来看一个例子:

 >>> def get_count():
... fs = []
... for i in range(,):
... def f ():
... return i*i
... fs.append(f)
... return fs
... f1,f2,f3 = get_count()

在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。

你可能认为调用f1()f2()f3()结果应该是149,但实际结果是:

 >>> f1()

 >>> f2()

 >>> f3()
 

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

 >>> def count():
... fs = []
... for i in range(,):
... def f(j):
... def g():
... return j*j
... return g
... fs.append(f(i))
... return fs
...
>>> f1,f2,f3 = count()
>>> f1
<function g at 0x7f810add19b0>
>>> f1() >>> f2() >>> f3() >>>

缺点是代码较长,可利用lambda函数缩短代码。

3. 匿名函数:

当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:

 >>> map(lambda x : x * x,[,,,,,,,,,])
[, , , , , , , , ]
>>> map(lambda x : x * x,range())
[, , , , , , , , , ]
>>>

通过对比不难看出,匿名函数lambda x : x * x实际上就是一个求平方的函数:

 >>> def f(x):
... return x*x
...
>>> f() >>> f() >>>

关键字lambda表示匿名函数,冒号前面的x表示函数参数。

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

 >>> hanshu = lambda x : x*x*x
>>> hanshu
<function <lambda> at 0x7f810add1b90>
>>> hanshu() >>> hanshu() >>>

同样,也可以把匿名函数作为返回值返回,比如:

 >>> def build(x,y):
... return lambda: x*x + y*y
...
>>> build(,)
<function <lambda> at 0x7f810add1c80>
>>>

4. 偏函数

Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下:

int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:

 >>>
>>> int('') >>> int('') >>>

int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:

 >>> int('',base = )

 >>> int('',base = )

 >>> int('',base = )

 >>> int('',base = )

 >>> 

假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

 >>> def int2(x ,base = ):
... return int(x,base)
...
>>> int2()
Traceback (most recent call last):
File "<stdin>", line , in <module>
File "<stdin>", line , in int2
TypeError: int() can't convert non-string with explicit base
>>> int2('') >>>

注意:在传入参数的时候,要以字符串的形式传入,否则会报出“TypeError”的类型错误。要使用偏函数的时候还得自己定义,是不是感觉很麻烦?因此,python提供了functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2

 >>> import functools
>>> int2 = functools.partial(int,base = )
>>> int3 = functools.partial(int,base = )
>>> int2('') >>> int3('') >>>

所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

 >>> int3('',base = )

 >>> int2('',base = )

 >>> 

最后,创建偏函数时,实际上可以接收函数对象、*args**kw这3个参数,当传入:

int2 = functools.partial(int, base=)

实际上固定了int()函数的关键字参数base,也就是:

int2('')

相当于:

kw = { base: } int('', **kw)

当传入:

max2 = functools.partial(max, )

实际上会把10作为*args的一部分自动加到左边,也就是:

 max2(, , )

相当于:

args = (, , , )

max(*args)

结果 = 10

python学习之---匿名函数,返回函数,偏函数的更多相关文章

  1. Learning Python 012 函数式编程 2 返回函数 匿名函数 装饰器 偏函数

    Python 函数式编程 2 返回函数 返回函数的意思就是:函数作为返回值.(高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回.) 举个例子:实现一个可变参数的求和. 正常的函数: de ...

  2. JS进阶-特殊形式的函数-返回函数的函数/重写自己的函数

    返回函数的函数 // 返回函数的函数 function a() { alert("aa"); return function () { alert("bb"); ...

  3. Python学习 Day 5 高阶函数 map/reduce filter sorter 返回函数 匿名函数 装饰器 偏函数

    高阶函数Higher-orderfunction 变量可以指向函数 >>> abs #abs(-10)是函数调用,而abs是函数本身 <built-in function ab ...

  4. Python复习笔记(四)高阶函数/返回函数/匿名函数/偏函数/装饰器

    一.map/reduce map map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次 作用到序列的每个元素,并把结果作为新的Iterator返回. reduce r ...

  5. python学习:匿名函数

    Python 函数 lambda   匿名函数 -lambda 函数是一种快速定义单行的最小函数,可以用在任何需要函数的地方.   def fun(x,y):        return x*y fu ...

  6. Python学习【第九篇】函数

    函数 函数是什么? 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上而下实现功能,其往往用一段代码来实现指定功能,开发过 ...

  7. Python学习,第八课 - 函数

    本次讲解函数,由于内容比较多,小编列了个大纲,主要有一下内容: 1. 函数基本语法及特性 2. 函数参数 3.局部变量 4. 返回值 5.嵌套函数 6.递归 7.匿名函数 8.高阶函数 9.内置函数 ...

  8. python学习-day14:集合,函数,格式化

    一.集合 定义:由不同元素组成的集合.集合是一组无序排列的可hash值, 可以作为字典的key.元素必须是不可变类型:只能存放数字,字符串,字典 特性:集合的目的是将不同的值放在一起,不同的集合之间可 ...

  9. Python学习入门教程,字符串函数扩充详解

    因有用户反映,在基础文章对字符串函数的讲解太过少,故写一篇文章详细讲解一下常用字符串函数.本文章是对:程序员带你十天快速入门Python,玩转电脑软件开发(三)中字符串函数的详解与扩充. 如果您想学习 ...

随机推荐

  1. Android开发之从网络URL上下载JSON数据

    网络下载拉取数据中,json数据是一种格式化的xml数据,非常轻量方便,效率高,体验好等优点,下面就android中如何从给定的url下载json数据给予解析: 主要使用http请求方法,并用到Htt ...

  2. Android(java)学习笔记138:html嵌入到java显示乱码

    解决方案: 使用 loadData方法是中文部分会出现乱码,即使指定“utf-8”.“gbk”.“gb2312”也一样. webView.getSettings().setDefaultTextEnc ...

  3. c语言,strcspn,在串中查找第一个给定字符集内容的段

    函数名: strcspn 功 能: 在串中查找第一个给定字符集内容的段 用 法: int strcspn(char *str1, char *str2); 程序例: #include <stdi ...

  4. 【邮件】imap与pop3的区别

    文:铁乐猫 2015 10月14日 今天替一位在外出差的用户安装和设置完foxmail用于收发邮件,到下午被告知对方用foxmail发完邮件后,在网页上登录邮箱后并没有看到在foxmail中" ...

  5. 跨时钟域设计【一】——Slow to fast clock domain

    跨时钟域设计是FPGA设计中经常遇到的问题,特别是对Trigger信号进行同步设计,往往需要把慢时钟域的Trigger信号同步到快时钟域下,下面是我工作中用到的慢时钟域到快时钟域的Verilog HD ...

  6. http://venkatbaggu.com/file-upload-in-asp-net-mvc-using-dropzone-js-and-html5/

    http://venkatbaggu.com/file-upload-in-asp-net-mvc-using-dropzone-js-and-html5/ http://www.cnblogs.co ...

  7. magento中的一些技巧

    1.加载某个attribute: $attributeCode=Mage::getModel('catalog/resource_eav_attribute')                     ...

  8. 【转】浅谈Java中的hashcode方法(这个demo可以多看看)

    浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...

  9. 如何创建windows xp 虚拟机

         如何创建windows xp 虚拟机 一.所需软件 1. VMware-workstation-full-12.0.0-2985596 赠送vm12 激活key一枚: 5A02H-AU243 ...

  10. git github 使用教程

    参考文章:文章地址: http://wuyuans.com/2012/05/github-simple-tutorial/ github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般 ...