Python 函数,参数,返回值介绍,以及 Python 函数的定义和调用

我被代码海扁署名-非商业-禁演绎
阅读 11:24·字数 3424·发布 
Bilibili 空间
关注 960

前提

阅读本节的前提是已经掌握函数,参数等概念,你可以查看编程教程函数,参数,返回值介绍一节来了解他们。

定义 Python 函数

通常情况下,Python 函数定义在模块中,并作为可被外部调用的目标,其基本的书写格式如下。

def <funcname>(<parameterlist>)
    <docstring>
    <block>

funcname 部分

funcname为函数名称,他需要符合 Python 的标识符规范,不能使用 Python 关键字或保留关键字。

parameterlist 部分

parameterlist是函数的参数表,他定义了函数的所有参数,参数之间使用,进行分隔。

docstring 部分

docstring是函数的文档字符串,包含了对函数的说明,这并非强制性的要求,一个函数可以没有文档字符串。

block 部分

block为函数的主体代码,他和docstring都需要使用某种空白字符进行缩进,以表示其归属于函数。

下面是一个简单的 Python 函数hello,拥有一个名称为name的参数。

functions.py
# 定义一个具有参数 name 的函数 hello
def hello(name):
	'''一个超级简单的函数'''
	print(f'你好,{name}')

调用 Python 函数

在任何语言中,调用函数都是一件轻松的事情,Python 也是如此,以下是调用函数的基本格式。

<funcname>(<argumentlist>)

funcname 部分

funcname为需要调用的函数名称。

argumentlist 部分

argumentlist是向函数传递的实参表。

在下面的代码中,我们调用了函数hello,并传递了实参'Kitty'

functions.py
# 调用函数 hello
hello('Kitty')
你好,Kitty

Python 代码缩进

Python 通过缩进来说明代码层级结构,缩进一般通过空格符或制表符实现。从行首开始计算,拥有相同数量空格符或制表符的代码被视为同一层次。

不要在 Python 中混合使用空格符和制表符进行缩进

虽然,在一个 Python 脚本文件中,混合使用空格符和制表符进行缩进是被允许的,比如,使用两个空格表示一个层次,使用三个制表符表示另一个层次。但这并不是可取的行为,因为他可能会导致不必要的错误,或让代码的可读性下降。

Python 函数的参数

Python 函数的参数可以拥有默认值,在定义时使用=进行设置即可,默认值仅运算一次,因此参数的默认值会指向同一个对象。如果默认值是一个列表,那么每次调用函数时,列表包含的元素可能会不同。

如何限制 Python 函数的参数为位置参数?

为 Python 函数增加特殊符号/,该符号之前的参数只能作为位置参数使用。

如何限制 Python 函数的参数为关键字参数?

为 Python 函数增加*标记的可变参数(可以仅保留*自身),该参数之后的参数只能作为关键字(命名)参数使用。在一个函数中,使用*标记的参数只能出现在符号/之后,否则位置参数将无法被确定。

下面的函数add,其参数xy拥有默认值,且只能作为位置参数使用,参数z只能作为关键字参数使用。当参数y使用其默认值时,列表中的元素会随着调用次数的增多而增多。

functions.py
# 定义加法函数
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,其参数numsinfo均为可变参数。在调用时,我们为mlp传递了多个数字,以进行乘法计算。

functions.py
# 定义乘法函数
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 函数返回指定的值,如果未使用returnreturn未给出返回值,则函数默认返回None

Python 函数的签名

在默认情况下,Python 函数的签名仅包含函数名称,这意味着在同一个命名空间中,之后定义的函数会覆盖之前定义的同名函数,无论其参数和返回值如何。

在下面的代码中,第二次定义的函数wait将覆盖第一次定义的wait,因此,最后的语句wait(3)调用的是第二个wait函数。

functions.py
# 该函数将被之后定义的 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 会将赋值语句,认定为定义新的变量。

要实现在函数中修改外部变量,你需要使用globalnonlocal关键字。

命名空间,作用域

想要深入了解命名空间和作用域,你可以查看编程教程命名空间,作用域介绍一节。

下面的函数show并没有修改模块中定义的message变量,而是定义了自己的message

functions.py
# 在模块中定义变量 message
message = '我是一个模块变量'

# 函数 show 定义了自己的 message def show(): # 这并不会修改模块定义的 message message = '我是函数中的变量' print(message)
# 函数 show_again 使用了模块定义的 message def show_again(): print(message)
show() show_again()
我是函数中的变量
我是一个模块变量

Python 函数注释

书写 Python 函数的文档字符串,可以让开发人员轻松了解函数的用法,当然这需要开发工具具备相应的代码提示功能。

文档字符串本质上是书写在函数中的字符串字面量,他必须是函数主体的第一行代码,可以采用紧密相邻或加入空白的方式进行拼接,比如,'这是一个非常有用的'"函数",但不应包含需要运算的内容或操作,比如,'这是一个非常有用的'+"函数"f'他可以对 {count} 个目标进行计算'

当使用三重引号时,文档字符串可以是多行的,字符串中的空白字符均会保留,但这仅体现在函数对象的__doc__变量中,开发工具应对空白字符进行处理,以向开发人员展现更加友好的信息。

如何为 Python 函数的参数和返回值添加批注?

与函数的文档字符串不同,批注主要用于说明函数参数和返回值的类型,多个类型可以使用|分隔。参数批注的方式为,在参数名称后书写:,然后跟随参数的类型,比如name: str。返回值批注的方式为,在def语句末尾的:之前书写->,然后跟随返回值的类型,比如def hi() -> str | None

所有批注会作为一个字典保存在函数对象的__annotations__变量中,字典键值对的键是一个字符串,其内容为return(表示返回值)或参数名称,键值对的值为表示返回值或参数类型的类型对象。

functions.py
# 一个简单的函数
def simple(a: int = 1) -> None:
	'''一个简单的函数~~~!

果然,很简单。
'''

Python 嵌套函数

嵌套函数是定义在另一个函数或方法中的函数,其采用的语法和普通函数没有区别,被定义的嵌套函数的可访问性,一般等同于同一命名空间中的变量。

当然,你可以通过返回值或其他方式,使嵌套函数在更多位置得以调用,但这有违定义嵌套函数的初衷。

函数check是定义在函数add_list中的嵌套函数,用于排除元组中大于10的数字。

functions.py
# 计算元组中所有小于等于 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 表达式定义了一个完成除法运算的匿名函数。

functions.py
# 使用 lambda 表达式定义匿名函数
div = lambda a, b: a / b

print(div(9, 3))
3.0

源码

functions.py·codebeatme/python·GitHub