在Python中,函数可以实现某个特定功能,它由特定的语句构成,可以重复使用。函数可以把较大的程序分解成小级别的块,有助于用户对整体结构进行规划和管理。Python中的函数可以分为内置函数、标准库函数、第三方库函数和用户自定义函数等。前三个可以直接使用或导入模块后使用,而用户自定义函数则由用户根据自身需求自行开发。
函数定义的语法格式为:
函数由def定义,空格后是自定义的函数名。参数放置在小括号中,多个参数由逗号隔开。函数可以没有参数,但仍需有小括号,最后的冒号不可或缺。
函数语句是函数要执行的语句,如果其中包含return语句,则遇到时会终止执行函数语句,并返回return语句中的值。如果不包含return语句,函数会返回None。
例如,把上一节中的for语句定义为函数,如下:
函数由多行语句组成,为了加强可读性,往往在函数语句开头添加本函数的说明,用注释符号“#”或三引号都可以,本例第3行告知了本函数的用途。
本函数没有定义参数,执行时直接以defA()的方式调用。函数体第8行为return语句,返回了列表listB中的元素数量,第9行中把函数的返回值赋给了变量count,并在第10行打印出来。上例执行结果为:
Python还支持一种简单的函数定义方式 ——匿名函数 。顾名思义,匿名函数没有函数名,它以 lambda表达式 的形式创建,其语法格式为:
其中,arg1、arg2、…为函数的参数,多个参数之间用逗号分隔,参数和表达式之间以冒号隔开,表达式相当于函数语句。匿名函数中的函数语句只允许有一个,且不能过于复杂。lambda表达式实际生成了一个函数对象,该对象赋值给变量result,可以用result调用,例如:
该例创建了一个匿名函数,作用是计算两个数的平方和,函数对象赋值给变量squA,接着用squA调用该匿名函数,小括号中输入两个数值30和40,运行结果为2500。
多数时候函数需要带有参数。从函数定义和调用的角度来说,参数可以分为形式参数和实际参数,例如:
在定义函数时,定义的参数称为形式参数(简称形参),它们只在函数内部有效,例如第1行的a、b和c。而在调用函数时,传递给函数的参数称为实际参数(简称实参),它们可以是具体的数值、变量或表达式,如第3行的10、20和30。代码运行结果为60。
上例的形参并没有预先赋值,实际上形参可以设为默认值,例如:
第1行的形参c设为默认值30,第3行调用函数时,如果该参数无变更,可以只传入其他实参,运行结果同样为60。如果想更改第三个参数,第3行可以改为:
这样运行结果则为110。
需要注意的是,带有默认值的形参一定要位于参数列表的后面,不然Python会提示报错,例如:
如果形参的数量不能确定,可以使用 可变参数 。可变参数分为两种情况,第一种为∗args,函数在调用时可传入多个参数,这些参数保存为元组,例如:
注意第2行函数语句中的args前不能有∗。args是元组,用sum()可以实现元素相加。第3行调用时可以直接传入多个数值,代码运行结果为100。
第二种可变参数为∗∗kwargs,函数在调用时接收多个关键字参数,这些参数保存为字典,例如:
同样,第2行函数语句中的kwargs前不可出现∗∗。由于关键字参数以字典的形式出现,故需要用kwargs.values()的方式获取字典中键值对的值,再用sum()进行相加。第3行调用时,需通过变量的方式传入多个数值,代码运行结果为100。
Python之所以非常流行,原因之一在于它除了官方内置的核心模块,还有海量的第三方模块,基本可以实现所有常见的功能,能够帮助用户处理诸如云计算开发、Web开发、大数据、人工智能和金融分析等工作。选择合适的模块进行开发,可以节省大量时间,极大地提高效率。
通常一个模块就是一个Python文件,使用前需要导入模块。导入的形式分为import xxx和from xxx import xxx两类,以导入内置模块math和使用开根函数math.sqrt()为例:
当一个项目含有多个自定义模块时,为了便于导入,需要以包的形式进行组织管理。把多个模块放置到一个文件夹中,就形成了包。在Python 2.x中,含有多个模块的文件夹中还需要有名为__init__.py的文件,该文件中的内容可以为空。同样,如果包中还有子文件夹,其中仍有模块,那么子文件夹中也要有文件__init__.py,以此类推。但在python 3.x中,即使没有__init__.py文件,也可以作为包导入模块。还需要注意的是,包名不能与Python内置模块或第三方模块的名称相同,否则会导致命名冲突。
图2-16 含有多个模块的包
以Python 2.x为例。图2-16所示为一个文件夹packA,其中含有两个模块和一个子文件夹packB,packB中也有两个模块,两个文件夹中都有__init__.py,这样便构成了包。
在导入语句中,以点号“.”作为包的路径分隔符,例如:
如果模块Module_A1中含有名为Def_A1()的函数,也可以单独导入,例如: