注:本人用Python3.4作为学习版本,以下学习心得只适用于Python3.4。
写下这篇博客,意味着我即将步入函数式编程的大门。
说起函数,首先想到的莫过于读书至今依然围绕在我身边的那个“函数”。数学计算中的函数,简单地说,就是对给定数的一种人为约定的运算法则,将给定的数通过某种变化得到一个新的结果。Python中的函数有内置函数,简单的说和数学上的函数功能类似,比如说abs,就是将给定的值取绝对值,验证如下:
# Author: Lucas w res = abs(-10) print(res)
运行结果如下所示:
10
Process finished with exit code 0
类似的函数在Python中有好多,函数式编程和数值运算中的函数有着相同的灵魂,作为初级入门,我暂且将函数式编程定义为:将一段代码封装起来,就变成一个函数,起个名字,就是函数名,当需要调用这段代码时,直接调用函数名即可。以下是验证程序:
# Author: Lucas w #一段代码 a=1 b=2 c=a+b print(c) #将代码封装变成一个简单函数 def res(): a=1 b=2 c=a+b print(c) res()
结果如下:
3
3
Process finished with exit code 0
说了这么多,接下来谈一下函数的基本形式,代码如下:
# Author: Lucas w def test(x): x+=1 print(x) return 0 test(1)
运行结果如下:
2
Process finished with exit code 0
其中test表示函数名,x为形式参数,return为函数的返回值,这就是函数最简单的标准形式。接下来我们对函数进行全面的剖析。
首先我们来探讨函数的返回值return。
当我们需要接收函数返回值时,我们需要将函数赋给一个变量。验证程序如下:
# Author: Lucas w def test(): return 0 y= test() print(y)
运行结果如下:
0
Process finished with exit code 0
接下来要考虑的问题是,return都可以返回什么样的值。经过学习,初步确定为三种:当没有定义返回值时,返回空值None;当定义为对象时,返回该对象;当定义不止一个对象时,返回一个元组。验证程序如下:
# Author: Lucas w def test1(): return x= test1() def test2(): return 1 y= test2() def test3(): return 1,2,3,4,5 z= test3() print(x) print(y) print(z)
运行结果如下:
None 1 (1, 2, 3, 4, 5) Process finished with exit code 0
至此,我们已经熟悉了函数return都可以返回的值,至于定义函数为什么要加return这个返回值,大概是某些特定的时候,需要得到函数的计算结果,所以return才应运而生,我们姑且这么理解,毕竟刚入门,不可能追究过深。
接下来,我们来挖掘一下函数的参数所蕴含的秘密。
说起参数,我们都知道函数有形式参数,有实际参数。至于这两者的区别,一句话概括:实际参数占用内存空间,而形式参数不占用内存空间。这里我们用查询内存地址函数id来验证,程序如下:
# Author: Lucas w def test(x): print(x) print(id(x)) return test(1) print(id(1))
运行结果如下:
1
1755480256
1755480256
Process finished with exit code 0
可以看出,当函数运行时形式参数和实际参数有相同的内存地址。但是当函数运行后,形式参数被释放,不占用内存;而实际参数依然在内存中存在。验证如下:
# Author: Lucas w def test(x): print(x) return test(1) print(id(1)) print(id(x))
运行如下:
1 1755480256 Traceback (most recent call last): print(id(x)) NameError: name 'x' is not defined Process finished with exit code 1
可以看出,并没有在内存中找到x。这就看出了形式参数和实际参数的区别。形式参数用时占用内存,不用时释放内存;而实际参数,只要定义了,就一直在内存中存在。
接下来,我们来探讨参数的调用。这里主要有两种调用方式:位置参数调用,顾名思义就是按照函数定义时参数的位置,采用一一对应的原则进行调用;另一种是关键字调用,这种调用方式更加灵活。验证程序如下:
# Author: Lucas w def test(x,y,z): print(x) print(y) print(z) return print("位置参数调用") test(1,2,3) print("关键字调用") test(x=1,z=3,y=2)
运行结果如下:
位置参数调用 1 2 3 关键字调用 1 2 3 Process finished with exit code 0
另外需要注意的是,关键字参数只能写在位置参数后边,不然程序就会报错。验证如下:
# Author: Lucas w def test(x,y,z): print(x) print(y) print(z) return print("位置参数在关键字参数前,可以调用") test(1,y=2,z=3)
运行结果如下:
位置参数在关键字参数前,可以调用 1 2 3 Process finished with exit code 0
位置参数在关键字参数后,则不能完成函数调用,验证程序如下:
# Author: Lucas w def test(x,y,z): print(x) print(y) print(z) return print("位置参数在关键字参数后,不可以调用") test(x=1,2,3)
运行结果如下:
test(x=1,2,3) ^ SyntaxError: non-keyword arg after keyword arg Process finished with exit code 1
因此,在调用函数时只要记住一句话:位置参数在前,关键字参数在后。
当我们需要定义函数的参数,不只局限于x,y...登有限个参数时。Python提供了两种方式:一种是元组存储法;一种是字典存储法。
接下来我们来看元组存储法,程序如下:
# Author: Lucas w def test(*args): print(args) return test(1,2,3,4,5,6,7,8,9,0)
运行结果如下:
(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
Process finished with exit code 0
以此可知,我们输入的参数,都存储在了args这个tuple中,并且并不限制参数数目。
接下来我们来验证第二种方法,字典存储法。验证程序如下:
# Author: Lucas w def test(**args): print(args) return test(name="Wang",age="18",sex="men")
运行结果如下:
{'sex': 'men', 'name': 'Wang', 'age': '18'} Process finished with exit code 0
因此,当我们需要定义的函数有未知个参数时,可以采取两种方法。一种是定义为元组,采用*args;一种是定义为字典,采用**args。
至此,函数式编程基本形式,我们已经有了大概的了解。接下来明确一下局部变量和全局变量的关系。
在Python中,
全局变量指的是:除函数内定义的变量之外,其余程序中所有该变量都代表同一个变量。全局变量一般在程序一开始定义。
局部变量指的是:函数内定义的变量,生效范围只在函数内,当函数不运行时,该变量不生效。
另外需要注意的是,如果同时将一个变量定义为全局变量和局部变量,那么程序在执行时,函数内将其作为局部变量,函数外将其作为全局变量。实际运行时,也就是同名,实际代表的功能并不一样。这就好比老王有个儿子叫小王,而班里还有一个同学叫小王,我们并不能说这两个小王都是老王的儿子,也仅仅只是同名而已。慢慢体会,似乎同名的全局变量和局部变量也是一样的道理。验证程序如下:
# Author: Lucas w XiaoWang = "小王的同学" def test(x): XiaoWang = "老王的儿子" print("局部变量") print(XiaoWang) return test(XiaoWang) print("全局变量") print(XiaoWang)
运行结果如下:
局部变量
老王的儿子
全局变量
小王的同学
Process finished with exit code 0
这个全局变量和局部变量重名一般不会出现,之所以拿出来比较,也仅仅是加深理解概念罢了,并没有实际意义。另一个更加鸡肋的功能,将局部变量转换为全局变量。
这个用法,在Python中存在,但是实际用处并不大,只能将我等入门级程序员弄的满脸蒙蔽。转换方法如下所示:
# Author: Lucas w XiaoWang = "小王的同学" def test(x): global XiaoWang XiaoWang = "老王的儿子" print("转换为全局变量的局部变量") print(XiaoWang) return test(XiaoWang) print("全局变量") print(XiaoWang)
运行结果如下:
转换为全局变量的局部变量
老王的儿子
全局变量
老王的儿子
Process finished with exit code 0
这个global功能,暂且知道用法,不进行细究。接下来我们进入递归函数的学习。
所谓递归函数,字面意思可以理解为函数自身来调用自身,需要注意的是,Python中默认递归次数为999,虽然说我们可以通过设置来增加递归次数,但这显然不是最理想的做法,因为我们打破了Python对系统的一种保护机制。因此,我们在使用递归函数时必须明确指定一个结束条件,以免造成对系统损坏。以下是一种简单的递归函数:
# Author: Lucas w def test(x): print(x) x-=1 if x>0: return test(x) test(5)
运行结果如下:
5
4
3
2
1
Process finished with exit code 0
了解完递归函数之后,进入最后一个知识点:高阶函数。
所谓高阶函数,就是将运算法作为参数引入函数的定义中,通过以下例子,我们就可以直观的看到。验证程序如下:
# Author: Lucas w def test(x,y,f): return f(x)+f(y) res=test(1,-3,abs) print(res)
运行结果如下:
4
Process finished with exit code 0
自此,我们对Python中函数的概念有了一个大致的了解,算作是小小的入门吧,毕竟只是了解了一些概念,随着学习的深入,慢慢进步,共勉。