URLhttps://learnscript.net/zh/python/functions/
    复制链接转到说明  示例

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

    我被代码海扁署名-非商业-禁演绎
    阅读 11:17·字数 3389·更新 

    前提

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

    定义 Python 函数

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

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

    funcname 部分

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

    parameterlist 部分

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

    docstring 部分

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

    block 部分

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

    下面是一个简单的函数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 函数的参数

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

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

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

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

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

    下面的函数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 函数的可变参数

    在函数的参数前添加***后,参数将成为可变参数。其中符号*标记的参数是一个元组,他包含了调用该函数时,所有未在参数表中的位置参数。符号**标记的参数是一个字典,他应该位于参数表的最后,包含了调用该函数时,所有未在参数表中的关键字参数,字典键值对的键是一个字符串,表示了参数的名称,键值对的值为参数对应的值。

    如果在参数表中同时使用了***,则*后需要具有参数名称。

    如何为函数传递列表,元组,区域,字典中的值?

    如果为函数参数准备的值,存储在序列或映射对象中,那么可通过解构操作来简化参数的传递。具体做法为,使用*解构序列对象(包括列表,元组,区域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语句,可以为函数返回指定的值,如果未使用returnreturn未给出返回值,则函数默认返回None

    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 会将赋值语句,认定为定义新的变量。

    要实现在函数中修改外部变量,你需要使用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 函数注释

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

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

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

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

    与函数的文档字符串不同,批注主要用于说明函数参数和返回值的类型,多个类型可以使用|分隔。参数批注的方式为,在参数名称后书写:,然后跟随参数的类型,比如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