函数的定义、参数、返回值
- 函数的定义
- 函数的调用
- 为函数提供说明文档
- 位置参数
- 关键字参数
- 默认参数
- 可变参数(*args,**kwargs)
- 逆向参数收集
- None(空值)及用法
- 返回值 return
函数的定义
定义函数,也就是创建一个函数,可以理解为创建一个具有某些用途的工具。定义函数需要用 def 关键字
实现,具体的语法格式如下:
def 函数名(参数列表):
//实现特定功能的多行代码
[return [返回值]]
此格式中,各部分参数的含义如下:
- 函数名:其实就是一个符合 Python 语法的标识符,但不建议使用 a、b、c 这类简单的标识符作为函数名,函数名最好能够体现出该函数的功能(如
my_len
,即表示我们自定义的len()
函数)。 - 形参列表:设置该函数可以接收多少个参数,多个参数之间用逗号(
,
)分隔。 - [
return [返回值]
]:整体作为函数的可选参参数,用于设置该函数的返回值。也就是说,一个函数,可以用返回值,也可以没有返回值,是否需要根据实际情况而定。
注意,在创建函数时,即使函数不需要参数,也必须保留一对空的“
()
”,否则 Python 解释器将提示“invaild syntax”错误。另外,如果想定义一个没有任何功能的空函数,可以使用 pass 语句作为占位符。
例如,下面定义了 2 个函数:
#定义个空函数,没有实际意义
def pass_dis():
pass
#定义一个比较字符串大小的函数
def str_max(str1,str2):
str = str1 if str1 > str2 else str2
return str
函数的调用
调用函数也就是执行函数。如果把创建的函数理解为一个具有某种用途的工具,那么调用函数就相当于使用该工具。
函数调用的基本语法格式如下所示:
[返回值] = 函数名([形参值])
其中,函数名即指的是要调用的函数的名称;形参值指的是当初创建函数时要求传入的各个形参的值。如果该函数有返回值,我们可以通过一个变量来接收该值,当然也可以不接受。
需要注意的是,创建函数有多少个形参,那么调用时就需要传入多少个值,且顺序必须和创建函数时一致。即便该函数没有参数,函数名后的小括号也不能省略。
为函数提供说明文档
通过调用 Python 的 help() 内置函数
或者 __doc__ 属性
,我们可以查看某个函数的使用说明文档。事实上,无论是 Python 提供给我们的函数,还是自定义的函数,其说明文档都需要设计该函数的程序员自己编写。
其实,函数的说明文档,本质就是一段字符串,只不过作为说明文档,字符串的放置位置是有讲究的,函数的说明文档通常位于函数内部、所有代码的最前面。
以上面程序中的 str_max() 函数为例,下面演示了如何为其设置说明文档:
#定义一个比较字符串大小的函数
def str_max(str1,str2):
'''
比较 2 个字符串的大小
'''
str = str1 if str1 > str2 else str2
return str
help(str_max)
#print(str_max.__doc__)
程序执行结果为:
Help on function str_max in module __main__:
str_max(str1, str2)
比较 2 个字符串的大小
位置参数
位置参数,有时也称必备参数,指的是必须按照正确的顺序将实际参数传到函数中,换句话说,调用函数时传入实际参数的数量和位置都必须和定义函数时保持一致。
实参和形参数量必须一致
在调用函数,指定的实际参数的数量,必须和形式参数的数量一致(传多传少都不行),否则 Python 解释器会抛出 TypeError
异常,并提示缺少必要的位置参数。
例如:
def girth(width , height):
return 2 * (width + height)
#调用函数时,必须传递 2 个参数,否则会引发错误
print(girth(3))
输出:
Traceback (most recent call last):
File "c:\Users\qinjl\Desktop\1.py", line 4, in <module>
print(girth(3))
TypeError: girth() missing 1 required positional argument: 'height'
可以看到,抛出的异常类型为 TypeError,具体是指 girth()
函数缺少一个必要的 height
参数。
同样,多传参数也会抛出异常:
def girth(width , height):
return 2 * (width + height)
#调用函数时,必须传递 2 个参数,否则会引发错误
print(girth(3,2,4))
输出:
Traceback (most recent call last):
File "C:\Users\mengma\Desktop\1.py", line 4, in <module>
print(girth(3,2,4))
TypeError: girth() takes 2 positional arguments but 3 were given
通过 TypeErroe 异常信息可以知道,girth()
函数本只需要 2 个参数,但是却传入了 3 个参数。
实参和形参位置必须一致
在调用函数时,传入实际参数的位置必须和形式参数位置一一对应,否则会产生以下 2 种结果:
1、抛出 TypeError 异常
当实际参数类型和形式参数类型不一致,并且在函数种,这两种类型之间不能正常转换,此时就会抛出 TypeError 异常。
例如:
def area(height,width):
return height*width/2
print(area("C语言中文网",3))
输出:
Traceback (most recent call last):
File "C:\Users\mengma\Desktop\1.py", line 3, in <module>
print(area("C语言中文网",3))
File "C:\Users\mengma\Desktop\1.py", line 2, in area
return height*width/2
TypeError: unsupported operand type(s) for /: 'str' and 'int'
以上显示的异常信息,就是因为字符串类型和整形数值做除法运算。
2、产生的结果和预期不符
调用函数时,如果指定的实际参数和形式参数的位置不一致,但它们的数据类型相同,那么程序将不会抛出异常,只不过导致运行结果和预期不符。
例如,设计一个求梯形面积的函数,并利用此函数求上底为 4cm,下底为 3cm,高为 5cm 的梯形的面积。但如果交互高和下低参数的传入位置,计算结果将导致错误:
def area(upper_base,lower_bottom,height):
return (upper_base+lower_bottom)*height/2
print("正确结果为:",area(4,3,5))
print("错误结果为:",area(4,5,3))
输出:
正确结果为: 17.5
错误结果为: 13.5
因此,在调用函数时,一定要确定好位置,否则很有可能产生类似示例中的这类错误,还不容易发现。
关键字参数
目前为止,我们使用函数时所用的参数都是位置参数,即传入函数的实际参数必须与形式参数的数量和位置对应。
关键字参数:是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。
例如,在下面的程序中就使用到了关键字参数的形式给函数传参:
def dis_str(str1,str2):
print("str1:",str1)
print("str2:",str2)
#位置参数
dis_str("java","python")
输出:
str1: java
str2: python
#关键字参数
dis_str("java",str2="python")
dis_str(str2="java",str1="python")
输出:
str1: java
str2: python
输出:
str1: python
str2: java
可以看到,在调用有参函数时,既可以根据位置参数来调用,也可以使用关键字参数来调用。在使用关键字参数调用时,可以任意调换参数传参的位置。
当然,使用位置参数和关键字参数混合传参的方式。
但需要注意,混合传参时关键字参数必须位于所有的位置参数之后。也就是说,如下代码是错误的:
# 位置参数必须放在关键字参数之前,下面代码错误
dis_str(str1="java","python")
输出:
SyntaxError: positional argument follows keyword argument
默认参数
我们知道,在调用函数时如果不指定某个参数,Python 解释器会抛出异常。
为了解决这个问题,Python 允许为参数设置默认值
,即在定义函数时,直接给形式参数指定一个默认值。这样的话,即便调用函数时没有给拥有默认值的形参传递参数,该参数可以直接使用定义函数时设置的默认值。
Python 定义带有默认值参数的函数,其语法格式如下:
def 函数名(...,形参名,形参名=默认值):
代码块
注意,在使用此格式定义函数时,指定有默认值的形式参数必须在所有没默认值参数的最后,否则会产生语法错误。
可变参数(*args,**kwargs)
可变参数,又称不定长参数,即传入函数中的实际参数可以是任意多个
1、可变参数:形参前添加一个 '*'
此种形式的语法格式如下所示:
*args
args 表示创建一个名为 args 的空元组
,该元组可接受任意多个外界传入的非关键字实参。
下面程序演示了如何定义一个参数可变的函数:
# 定义了支持参数收集的函数
def dis_str(home, *str) :
print(home)
# 输出str元组中的元素
print("str=",str)
for s in str :
print(s)
#可传入任何多个参数
dis_str("java","python","scala")
输出:
java
str= ('python', 'scala')
python
scala
上面程序中,dis_str() 函数
的最后一个参数就是 str 元组
,这样在调用该函数时,除了前面位置参数接收对应位置的实参外,其它非关键字参数都会由 str 元组
接收。
当然,可变参数并不一定必须为最后一个函数参数,例如修改 dis_str() 函数为:
# 定义了支持参数收集的函数
def dis_str(*str,home) :
print(home)
# 输出str元组中的元素
print("str=",str)
for s in str :
print(s)
dis_str("java","python",home="scala")
可以看到,str 可变参数
作为 dis_str()
函数的第一个参数。但需要注意的是,在调用该函数时,必须以关键字参数的形式给普通参数传值,否则 Python 解释器会把所有参数都优先传给可变参数,如果普通参数没有默认值,就会报错。
也就是说,下面代码调用上面的 dia_str()
函数,是不对的:
dis_str("java","python","php")
Python 解释器会提供如下报错信息:
TypeError: dis_str() missing 1 required keyword-only argument: 'home'
翻译过来就是我们没有给 home 参数传值。当然,如果 home 参数有默认参数,则此调用方式是可行的。
2、可变参数:形参前添加两个'*'
这种形式的语法格式如下:
**kwargs
**kwargs
表示创建一个名为 kwargs 的空字典
,该字典可以接收任意多个以关键字参数赋值的实际参数。
# 定义了支持参数收集的函数
def dis_str(home,*str,**course) :
print(home)
print(str)
print(course)
#调用函数
dis_str("java", "python", "php", shell="shell", go="go", c="c")
输出:
java
('python', 'php')
{'shell': 'shell', 'go': 'go', 'c': 'c'}
上面程序在调用 dis_str()
函数时,第 1 个参数传递给 home 参数,第 2、3 个非关键字参数传递给 str 元组,最后 2 个关键字参数将由 course 字典接收。
注意,*args 可变参数的值默认是空元组,**kwargs 可变参数的值默认是空字典。因此,在调用具有可变参数的函数时,不一定非要给它们传值。以调用 dis_str(home, *str, **course)
为例,下面的调用方式也是正确的:
dis_str(home="java")
输出:
java
()
{}
逆向参数收集
Python 还支持逆向参数收集,即直接将列表、元组、字典作为函数参数,Python 会将其进行拆分,把其中存储的元素按照次序分给函数中的各个形参。
在以逆向参数收集的方式向函数参数传值时,当传入列表或元组时,其名称前要带一个 * 号
,当传入字典时,其名称前要带有两个 * 号
。
def dis_str(name, age, address):
print("name:", name)
print("age:", age)
print("address:", address)
# 列表当参数
data = ["jack", "20", "china"]
# 使用逆向参数收集方式传值
dis_str(*data)
输出:
name: jack
age: 20
address: china
def dis_str(name, age, address):
print("name:", name)
print("age:", age)
print("address:", address)
# 字典当参数
data = {"name": "jack", "age": "20", "address": "china"}
# 使用逆向参数收集方式传值
dis_str(**data)
输出:
name: jack
age: 20
address: china
此外,以逆向参数收集的方式,还可以给拥有可变参数的函数传参,例如:
def dis_str(name, **age):
print("name:", name)
print("age:", age)
data = {"name": "jack", "age": "20", "address": "china"}
# 使用逆向参数收集方式传值
dis_str(**data)
输出:
name: jack
age: {'age': '20', 'address': 'china'}
如果使用逆向参数收集的方式,必须注意 * 号
的添加。以逆向收集列表为例,如果传参时其列表名前不带 * 号
,则 Python 解释器会将整个列表作为参数传递给一个参数。例如:
def dis_str(name, *age):
print("name:", name)
print("age:", age)
# print("address:", address)
data = ["jack", "20", "china"]
# 使用逆向参数收集方式传值
dis_str(data)
输出:
name: ['jack', '20', 'china']
age: ()
None(空值)及用法
有一个特殊的常量 None(N 必须大写)
。和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。
None 有自己的数据类型:
>>> type(None)
<class 'NoneType'>
需要注意的是,None
是 NoneType
数据类型的唯一值(其他编程语言可能称这个值为 nul
l、nil
或 undefined
),也就是说,我们不能再创建其它 NoneType 类型的变量,但是可以将 None 赋值给任何变量。如果希望变量中存储的东西不与任何其它值混淆,就可以使用 None。
另外,对于没有 return 语句的函数定义,Python 都会在末尾加上 return None
,使用不带值的 return 语句(也就是只有 return 关键字本身),那么就返回 None。
返回值 return
用 def 语句创建函数时,可以用 return 语句指定应该返回的值,该返回值可以是任意类型。需要注意的是,return 语句在同一函数中可以出现多次,但只要有一个得到执行,就会直接结束函数的执行。
def add(a,b):
c = a + b
return c
#函数赋值给变量
c = add(3,4)
print(c)
#函数返回值作为其他函数的实际参数
print(add(3,4))
输出结果:
7
7
通过 return 语句指定返回值后,我们在调用函数时,既可以将该函数赋值给一个变量,用变量保存函数的返回值,也可以将函数再作为某个函数的实际参数。