专栏首页DBA随笔Python之函数编程(2)

Python之函数编程(2)

Python之函数编程(2)

1

函数作为返回值

在Python中,可以将一个函数作为另外一个函数的返回值,举个例子:

在上面的命令中,我们定义一个return_sum()的函数,这个函数返回一个sum的函数,sum函数的作用是求一个可迭代对象的所有元素的和,当我们直接调用return_sum函数的时候,返回值f是一个函数,再次调用这个函数,我们可以得到序列的和。其中,内部的sum函数相当于引用了外部的参数,当return_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种情况在python中称之为“闭包”,需要和B-box区分开来哦。

值得注意的一点是,当我们再次调用这个return_sum函数的时候,它会重新返回一个函数f1,而这个f1和上面的f虽然都指向同一个函数,但是他们两个的值并不相等,如下:

可以看到,这两个返回函数的值并不相等,同样的,二者的调用结果互不影响。

闭包详解

从上面的例子我们可以看到,我们要想求内部函数的结果,必须重新调用那个函数f(),再来看一个例子:

上面这个例子中,我们定义了一个函数count,里面嵌套了三次循环,每次循环,都创建了一个新的函数来计算一个数字的平方值,然后,把创建的3个函数都返回了。可能我们认为它的返回值会是1,4,9,但是实际上的结果如下:

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

所以得到一个约定俗成的结论:返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

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

再看看这个结果:

虽然这种方法能够得到最终的结果,但是思路上还是有些绕,个人不建议使用。

2

装饰器

考虑这样一种需求:我们想在函数调用前后自动打印函数日志,但是又不希望修改函数的定义,这种在代码运行期间动态增加功能的方式,就称之为“装饰器”。

在进行实验之前,首先介绍一下函数的__name__属性,每一个函数对象都有一个__name__属性,可以拿到函数的名字,下面我们举个例子说明:

当我们用一个变量f代替Python中的内置绝对值函数abs时,可以调用__name__来查看真实的函数名称。

现在我们定义一个log函数来实现上面的需求:

观察这个log函数,它是一个装饰器,它接受一个函数f作为参数,并返回一个函数wrapper,此时需要借助python的@语法(暂时不用纠结这个语法,该语法我们后续会讲到),把这个装饰器放在函数定义的地方,再去调用这个f函数,我们可以得到如下结果:

我们可以看到,将@log放到abs函数前面,相当于执行了abs=log(abs)语句,这样的操作,原来的abs函数依旧存在,只是现在的f变量指向了新的函数abs,于是调用f会直接返回log(abs)的内容。

装饰器还有更复杂的用法,这里我们不做拓展。

3

偏函数

python的functools里面还定义了很多有用的功能,其中一个就是偏函数,其实说白了和自定义函数非常像,例如我们要看看字符串‘12345’转换成整数的值,可以通过int函数来查看,但是当我们把这个‘12345’看成八进制的,怎么求对应的十进制数字呢?看看下面的例子:

但是这样的参数传递还是有些不方便,自然而然会想到如果我们定义一个int2()的函数,默认把base=2传进去,就可以直接计算二进制的数值了,functool.partial就可以帮助我们创建这样的偏函数,我们可以利用下面的方法创建一个新的函数int2:

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

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

再看一个例子,当我们传入:

max2=functools.partial(max,10)时,实际上是将10作为*args的一部分自动加到参数列表前面,如下:

我们发现在用max2函数求5,6,7的最大值的时候,直接返回10,其实是因为它相当于求

max(10,5,6,7)当中的最大值,所以结果也就可以解释了。

本文分享自微信公众号 - DBA随笔(gh_acc2bbc0d447),作者:AsiaYe

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python之函数编程(1)

    第一次接触到这个知识点的时候,我还不是特别适应,内置的函数怎么可以用一个变量来代替?但是python确实是这么做的,这也不妨碍它的顺利执行。举个例子说明...

    AsiaYe
  • Python之面向对象简介

    Python之面向对象 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函...

    AsiaYe
  • Go语言学习计划和一些总结

    bool型、数字类型、字符串类型、派生类型(指针、数组、结构化、channel、函数、切片、接口、Map等)

    AsiaYe
  • 学会使用函数式编程的程序员(第1部分)

    在这篇由多部分组成的文章中,接下来将介绍函数式编程的一些概念,这些概念对你学习函数式编程有所帮助。如果你已经懂了什么是函数式编程,这可以加深你的理解。

    前端小智@大迁世界
  • Kotlin中let()with()run()apply()also()函数的使用方法与区别

    相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说经常会写出一些不够优雅的代码。在Kotlin中的源码标准库(Standard...

    砸漏
  • 码如其人,小老弟,你能写一手漂亮的Python函数吗

    好的 Python 函数与蹩脚 Python 函数的区别是什么?「好」函数的定义之多让人惊讶。从我们的目的出发,我会把好的 Python 函数定义为符合以下清单...

    一墨编程学习
  • 如何学python 第10课 创建自己的函数

    在上一节课里,我们学习了一些关于错误检测和错误处理的知识。这节课我们来学习函数。我们将会介绍什么是函数,以及如何创建函数。 函数是什么? 函数是一系列指令的集合...

    用户1631416
  • [高大上的DL] Activation function (激活函数)的初步认识

    今天简单认识一下什么激活函数以及都有那些激活函数。说到激活函数这里有几个比较容易混淆的概念,比如Pooling池化和Sampling采样,loss functi...

    用户1622570
  • (1)James Stewart Calculus 5th Edition:Functions and Models

    dodo_lihao
  • 3分钟读懂C语言函数:这些例子一看就懂!|一键删除账户教学

    最近发现,有些小伙伴对C语言的函数有些难以理解,其实呢,C语言的函数很好理解,只不过部分人在学习的时候,没有找到好的例子来类比理解而已。这篇文章会教大家如何去理...

    诸葛青云

扫码关注云+社区

领取腾讯云代金券