Python 函数,参数,返回值介绍,以及 Python 函数的定义和调用
前提
阅读本节的前提是已经掌握函数,参数等概念,你可以查看编程教程的函数,参数,返回值介绍一节来了解他们。
定义 Python 函数
通常情况下,Python 函数定义在模块中,并作为可被外部调用的目标,其基本的书写格式如下。
def <funcname>(<parameterlist>)
<docstring>
<block>
- funcname 部分
funcname
为函数名称,他需要符合 Python 的标识符规范,不能使用 Python 关键字或保留关键字。- parameterlist 部分
parameterlist
是函数的参数表,他定义了函数的所有参数,参数之间使用,
进行分隔。- docstring 部分
docstring
是函数的文档字符串,包含了对函数的说明,这并非强制性的要求,一个函数可以没有文档字符串。- block 部分
block
为函数的主体代码,他和docstring
都需要使用某种空白字符进行缩进,以表示其归属于函数。
下面是一个简单的 Python 函数hello
,拥有一个名称为name
的参数。
# 定义一个具有参数 name 的函数 hello
def hello(name):
'''一个超级简单的函数'''
print(f'你好,{name}')
调用 Python 函数
在任何语言中,调用函数都是一件轻松的事情,Python 也是如此,以下是调用函数的基本格式。
<funcname>(<argumentlist>)
- funcname 部分
funcname
为需要调用的函数名称。- argumentlist 部分
argumentlist
是向函数传递的实参表。
在下面的代码中,我们调用了函数hello
,并传递了实参'Kitty'
。
# 调用函数 hello
hello('Kitty')
你好,Kitty
Python 代码缩进
Python 通过缩进来说明代码层级结构,缩进一般通过空格符或制表符实现。从行首开始计算,拥有相同数量空格符或制表符的代码被视为同一层次。
不要在 Python 中混合使用空格符和制表符进行缩进
虽然,在一个 Python 脚本文件中,混合使用空格符和制表符进行缩进是被允许的,比如,使用两个空格表示一个层次,使用三个制表符表示另一个层次。但这并不是可取的行为,因为他可能会导致不必要的错误,或让代码的可读性下降。
Python 函数的参数
Python 函数的参数可以拥有默认值,在定义时使用=
进行设置即可,默认值仅运算一次,因此参数的默认值会指向同一个对象。如果默认值是一个列表,那么每次调用函数时,列表包含的元素可能会不同。
如何限制 Python 函数的参数为位置参数?
为 Python 函数增加特殊符号/
,该符号之前的参数只能作为位置参数使用。
如何限制 Python 函数的参数为关键字参数?
为 Python 函数增加*
标记的可变参数(可以仅保留*
自身),该参数之后的参数只能作为关键字(命名)参数使用。在一个函数中,使用*
标记的参数只能出现在符号/
之后,否则位置参数将无法被确定。
下面的函数add
,其参数x
,y
拥有默认值,且只能作为位置参数使用,参数z
只能作为关键字参数使用。当参数y
使用其默认值时,列表中的元素会随着调用次数的增多而增多。
# 定义加法函数
def add(x=1, y=[], /, *, z):
# 列表 y 添加数字 100
y.append(100)
print(y)
# 计算 x,y,z 含有的数字之和
num = 0
for i in y:
num += i
return x + num + z
# z 只能作为关键字参数使用
print(add(z=1))
# x 作为位置参数被使用
print(add(1, z=3))
[100]
102
[100, 100]
204
Python 函数的可变参数
在 Python 函数的参数前添加*
或**
后,参数将成为可变参数。其中符号*
标记的参数是一个元组,他包含了调用该函数时,所有未在参数表中的位置参数。符号**
标记的参数是一个字典,他应该位于参数表的最后,包含了调用该函数时,所有未在参数表中的关键字参数,字典键值对的键是一个字符串,表示了参数的名称,键值对的值为参数对应的值。
如果在参数表中同时使用了*
和**
,则*
后需要具有参数名称。
如何为 Python 函数传递列表,元组,区域,字典中的值?
如果为函数参数准备的值,存储在 Python 序列或映射对象中,那么可通过解包操作来简化参数的传递。具体做法为,使用*
解包序列对象(包括列表,元组,区域range
),使用**
解包映射对象(主要为字典)。
下面的函数mlp
,其参数nums
,info
均为可变参数。在调用时,我们为mlp
传递了多个数字,以进行乘法计算。
# 定义乘法函数
def mlp(*nums, **info):
# 显示关键字参数
print(info)
# 计算 nums 中包含的位置参数
num = 1
for i in nums:
num *= i
return num
# 传递了多个数字进行乘法计算
print(mlp(2, 3, 4, 5, tip='这里是一个小小的提示'))
{'tip': '这里是一个小小的提示'}
120
Python 函数的返回值
使用return
语句,可以为 Python 函数返回指定的值,如果未使用return
或return
未给出返回值,则函数默认返回None
。
Python 函数的签名
在默认情况下,Python 函数的签名仅包含函数名称,这意味着在同一个命名空间中,之后定义的函数会覆盖之前定义的同名函数,无论其参数和返回值如何。
在下面的代码中,第二次定义的函数wait
将覆盖第一次定义的wait
,因此,最后的语句wait(3)
调用的是第二个wait
函数。
# 该函数将被之后定义的 wait 覆盖
def wait(seconds):
print(f'等待 {seconds} 秒')
# 调用的是最先定义的 wait 函数
wait(3)
# 该函数将覆盖之前定义的 wait
def wait(hours, minutes=5):
print(f'等待 {hours} 小时 {minutes} 分')
# 调用的是最后定义的 wait 函数
wait(3)
等待 3 秒
等待 3 小时 5 分
Python 函数的命名空间
是的,Python 函数拥有自己的命名空间,因此,你在函数内定义的变量,可以与函数外部的变量同名,他们会被区别对待。
Python 函数不能直接赋值修改函数外部定义的变量
根据作用域的一般性原则,你可以在函数中访问函数外部定义的某个变量,但仅限于读取,当你尝试对外部变量写入时,并不能达到预期效果,原因在于 Python 会将赋值语句,认定为定义新的变量。
要实现在函数中修改外部变量,你需要使用global
或nonlocal
关键字。
命名空间,作用域
想要深入了解命名空间和作用域,你可以查看编程教程的命名空间,作用域介绍一节。
下面的函数show
并没有修改模块中定义的message
变量,而是定义了自己的message
。
# 在模块中定义变量 message
message = '我是一个模块变量'
# 函数 show 定义了自己的 message
def show():
# 这并不会修改模块定义的 message
message = '我是函数中的变量'
print(message)
# 函数 show_again 使用了模块定义的 message
def show_again():
print(message)
show()
show_again()
我是函数中的变量
我是一个模块变量
Python 嵌套函数
嵌套函数是定义在另一个函数或方法中的函数,其采用的语法和普通函数没有区别,被定义的嵌套函数的可访问性,一般等同于同一命名空间中的变量。
当然,你可以通过返回值或其他方式,使嵌套函数在更多位置得以调用,但这有违定义嵌套函数的初衷。
函数check
是定义在函数add_list
中的嵌套函数,用于排除元组中大于10
的数字。
# 计算元组中所有小于等于 10 的数字之和
def add_list(*l):
# 嵌套函数 check,检查数字,大于 10 则返回 0
def check(i):
return 0 if i > 10 else i
# 调用 check,忽略元组中大于 10 的数字
num = 0
for i in l:
num += check(i)
return num
print(add_list(4, 2, 11, 3))
9
Python Lambda 表达式
使用 lambda 表达式,你可以简便的定义一个匿名函数。与普通的函数不同,lambda 表达式定义的函数,不支持文档字符串以及参数或返回值的批注,并且仅允许单一的表达式,该表达式的运算结果即为函数的返回值,不需要使用return
语句。
在下面的代码中,我们使用 lambda 表达式定义了一个完成除法运算的匿名函数。
# 使用 lambda 表达式定义匿名函数
div = lambda a, b: a / b
print(div(9, 3))
3.0
Python 函数注释
书写 Python 函数的文档字符串,可以让开发人员轻松了解函数的用法,当然这需要开发工具具备相应的代码提示功能。
文档字符串本质上是书写在函数中的字符串字面量,他必须是函数主体的第一行代码,可以采用紧密相邻或加入空白的方式进行拼接,比如,
'这是一个非常有用的'"函数"
,但不应包含需要运算的内容或操作,比如,'这是一个非常有用的'+"函数"
,f'他可以对 {count} 个目标进行计算'
。当使用三重引号时,文档字符串可以是多行的,字符串中的空白字符均会保留,但这仅体现在函数对象的
__doc__
变量中,开发工具应对空白字符进行处理,以向开发人员展现更加友好的信息。如何为 Python 函数的参数和返回值添加批注?
与函数的文档字符串不同,批注主要用于说明函数参数和返回值的类型,多个类型可以使用
|
分隔。参数批注的方式为,在参数名称后书写:
,然后跟随参数的类型,比如name: str
。返回值批注的方式为,在def
语句末尾的:
之前书写->
,然后跟随返回值的类型,比如def hi() -> str | None
。所有批注会作为一个字典保存在函数对象的
__annotations__
变量中,字典键值对的键是一个字符串,其内容为return
(表示返回值)或参数名称,键值对的值为表示返回值或参数类型的类型对象。