内容提要
概述
函数
模块
综合举例
一、概述
Python的程序由包、模块和函数组成。 函数是一段可重用的有名称的代码。通过输入的参数值,返回需要的结果,并可存储在文件中供以后使用。几乎任何Python代码都可放在函数中。Python为函数提供了强大支持。 模块是处理某一类问题的集合,模块由函数和类组成。
模块和常规Python程序之间的唯一区别是用途不同:模块用于编写其他程序。因此,模块通常没有main函数。 包是一个完成特定任务的工具箱,Python提供了许多有用的工具包,如字符串处理、图形用户接口、Web应用、图像处理等。使用自带的工具包,可以提高程序开发效率、减少编程复杂度,达到代码重用的效果。
Python的程序结构:
说明:
Python自带的工具包和模块安装在其安装目录的Lib子目录中。
例如:Lib目录中的xml文件夹。xml文件夹就是一个包,该包用于完成XML的应用开发,xml包中包含四个子包:dom、sax、etree和parsers。文件__init__.py是xml包的注册文件,若无此文件,Python将不能识别xml包。
注意:包必须至少含有一个__init__.py文件。 __init__.py文件的内容可以为空,它用于标识当前文件夹是一个包。
二、函数
1、函数的定义及调用
格式: def 函数名(形参表): 函数体语句序列 [return 表达式] #可选项,即有的函数可以没有返回值。
函数调用: 函数名(实参表) 说明: 函数必须先定义,后使用; 函数名与变量名的命名规则相同,只能包含字母、数字和下划线_,且不能以数字打头。
例5-1:定义计算圆面积的函数
2、函数的参数
在C、C++中,参数的传递有值传递和引用传递两种方式。Python中任何东西都是对象,所以参数只支持引用传递的方式。
Python通过名称绑定的机制,把实际参数的值和形式参数的名称绑定在一起,即把形式参数传递到函数所在的局部命名空间中,形式参数和实际参数指向内存中同一个存储空间。
(1)按引用传递参数
向函数传递参数时,Python采用按引用传递的方式。这意味着当传递参数时,函数将使用新变量名来引用原始值。
例5-2:求任意两个数的和。
内存状态:
(2)默认值
函数的参数支持默认值。当某个参数没有传递实际的值时,函数将使用默认参数计算。 带默认值的参数不能位于没有默认值的参数前面。
例5-3:默认值参数示例。
(3)关键字参数
关键字参数有两大好处: 清晰地指出了参数值,有助于提高程序的可读性; 关键字参数的顺序无关紧要。 调用使用关键字参数的函数时,以param=value的方式传递参数
例5-4:关键字参数示例
3、函数的嵌套
C、C++都支持函数的嵌套调用,Python不仅支持函数的嵌套调用,还支持函数的嵌套定义。 当然,尽量不要在函数内部定义函数,这种方式不便于程序维护,容易造成逻辑上的混乱,且嵌套定义的函数层次越多,程序维护的代价就越大。
例5-5:分别使用函数的嵌套调用、函数的嵌套定义以及函数嵌套定义时直接引用外部函数的变量等三种方式,计算表达式(x+y)*(m-n)的值。
嵌套调用函数:
嵌套定义函数:
函数嵌套定义,内部函数直接引用外部函数的变量:
4、递归函数
(1)递归的概念
递归函数可以在函数主体内直接或间接地调用自己,即函数的嵌套是函数本身。 递归是一种程序设计方法,使用递归可以减少重复的代码,使程序变得简洁。 递归的过程分为两个阶段:递推和回归。
递归函数的原理: 第一阶段,递归函数在内部调用自己。每一次函数调用又重新开始执行此函数的代码,直到某一级递归程序结束。 第二阶段,递归函数从后往前返回。递归函数从最后一级开始返回,一直返回到第一次调用的函数体内。即递归函数逐级调用完毕后,再按相反的顺序逐级返回。
(2)递归的实现
一个问题能否用递归实现,看其是否具有下面的特点: 需有完成任务的递推公式。 结束递归的条件。 编写递归函数时,程序中必须有相应的语句: 一个递归调用语句。 测试结束语句。先测试,后递归调用。
例5-6:用递归方法求n!
源程序及执行结果:
例5-7:编程求出Fibonacci数列的第n项。
源程序及执行结果:
(3)递归的评价与消除递归
递归程序虽然易读、易编,但需要占用额外的内存空间,并且执行速度也受影响。 是否利用递归编程要看实际问题,如果要节约内存就用循环语句实现。若对内存要求并不高,可以用递归编程。 如果不用递归程序很难实现,则只能选择递归算法。
5、lambda函数
Lambda函数用于创建一个匿名函数,函数名未和标识符进行绑定。 使用lambda函数可以返回一些简单的运算结果。
格式: lambda 变量1,变量2…:表达式 功能:通常lambda赋值给一个变量,变量即可作为函数使用;也可以把lambda直接作为函数使用。
例5-8:用lambda函数改造例5-5-3。
例5-9:使用lambda定义求绝对值的匿名函数。
6、Generator函数
Generator函数的作用是一次产生一个数据项,并把数据项输出。
格式: def 函数名(参数列表): … yield 表达式
说明:Generator函数的定义与普通函数的区别只是在函数体内使用yield生成数据项。 Generator函数可以被for循环中遍历,且可以通过__next__()方法(Python 2是next方法)获得yield生成的数据项。
例5-10:用三种方法求斐波那契(Fibonacci)数列的前N项
说明:
结果没有问题,但直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。 要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 list(Python中的数据结构之一,是序列之一,由一组元素组成,值可改变。后续详细介绍)
方法二:定义一个函数,返回一个列表,列表中包含了斐波那契数列前 N 项
方法三:使用yield
说明:
方法三与方法一相比,仅仅把 print b 改为了 yield b,就在保持简洁性的同时获得了 iterable 的效果。 也可以手动调用 fab(5) 的 __next__() 方法,这样可以更清楚地看到 fab 的执行流程。 当函数执行结束时,generator 自动抛出 StopIteration 异常,表示迭代完成。在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。
三、模块
模块实际上是将一组函数放在一起共享公共的主题; 将这些函数存储于一个.py文件中; 使用import命令导入。
1、模块的创建及导入
创建模块,即创建一个.py文件,在其中包含用于完成任务的变量、类和函数,不包括main函数。 模块使用之前要导入该模块,导入方法之前已做过介绍。
例5-11:创建模块,用于在屏幕上打印各种形状。
定义的模块shapes及使用模块的源程序:
执行结果:
例5-12:创建一个求圆面积、圆周长、圆表面积和圆体积的模块
调用方式一:
调用方式二:
2、模块的属性
3、模块的内置函数
Python提供了一个内联模块buildin。该模块定义了一些常用函数,利用这些函数可以实现数据类型的转换、数据的计算、序列的处理等功能。
(1)filter()
声明: class filter(object) filter(function or None, iterable)-->filter object
功能:filter()可以对某个序列做过滤处理,根据自定义函数返回的结果是否为真来过滤,并一次性返回处理结果。返回结果是filter对象。
例5-13:filter()函数应用
(2)reduce()
声明: reduce(func,squence[,initial])->value
功能:对序列中的元素进行连续操作。
例如:可对某个序列中的元素进行累加、累乘和阶乘等操作。 说明:在Python 2中,reduce存在于全局空间中,可直接调用。而在Python 3中将其移到了functools模块中,所以使用之前要先引入。
例5-14:reduce()函数应用
(3)map()
声明: class map(object) map(func, iterables)-->map object
功能:对多个序列的每个元素都执行相同的操作,并返回一个map对象。
例5-15:map()函数应用。求列表中数字的幂运算。
常用内置模块函数(一):
常用内置模块函数(二):
4、自定义包
例:一个包与模块的树形关系
包pack的初始化程序及myModule模块:
包pack2的初始化程序及myModule2模块:
包parent中的main模块及执行结果:
4、第三方模块的导入
(1)单文件模块 直接把文件拷贝到 python的安装目录的Lib子目录下。
(2)多文件模块,带setup.py python setup.py install
例5-16:导入第三方模块requests
requests简介:requests是python的一个HTTP客户端库。支持 HTTP 连接保持和连接池,支持使用 cookie 保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。
步骤1:
去第三方库的网站( https://pypi.python.org )下载安装包,解压在python的安装目录。 注意第三方库的文件夹的位置以及setup.py的位置。
本例在Python 2.7下安装的。
步骤2:
步骤3:
安装完成
步骤4:
最后进入命令行,import库名称,观察第三方库是否安装成功。
四、综合举例
进一步完善:将求负数的奇数次根的情况考虑在内:
进一步完善:将分数的情况也考虑在内:
进一步完善:增加一个说明
2、递归经典程序—汉诺(Hanoi)塔问题
这是一个古典的数学问题,是一个只能用递归方法解决的问题。 问题源于印度一个古老传说,古代有一个梵塔,塔内有三个柱子A、B、C,开始时A柱上有64个盘子,盘子大小不等,大的在下,小的在上。想将这64个盘子从A柱移到C柱,但每次只允许移动一个盘子,且在移动过程中都始终保持大盘在下,小盘在上。在移动过程中可以利用B柱。
说明:
上述算法中的第1步和第3步,都是将n-1个盘子从一个座移到另一个座,只是座的名称不同而已。为使之一般化,可将第1步和第3步表示为: 将“one”座上n-1个盘移到“two”座(借助“three”座)。只是在第1步和第3步中,one、two、three和A、B、C的对应关系不同。 对第1步:one-A、two-B、three-C 对第3步:one-B、two-C、three-A。
程序及执行结果: