函数是已经组织好的可以被重复使用的一组代码块,它的作用是用来提高代码的重复使用率
在Python中,一切皆对象,同样函数也是对象,和int、bool等类型的对象处于同一地位(C语言中就不是这样的了)
在 Python 中,有很多内建函数(Built-in Function),这些函数在安装好 Python 后就能立即使用,我们也可以自定义函数实现特殊功能
定义函数的过程和其他类型对象的赋值定义过程的本质是类似的,定义函数就是创建了一个函数对象,并将该对象的引用保存到一个全局变量中,这个全局变量通常被称为函数名,只不过,与其他变量不同的是,该全局变量保存的 id 对应的内存空间的内容为一个代码块(即函数体代码)
在Python中,定义函数需要使用到关键字def
无论这个函数是否具有参数,都必须具有括号,否则会提示语法错误
函数定义时的一整个代码块和下面这个代码的本质相同
在进行函数定义的时候,不会执行函数体中的代码
Python函数必须要先定义,再调用,否则会引发异常
其实引发异常的本质和下面的这个代码是一样的,因为Python一切皆对象,函数也是对象
定义函数的时候可以指定形式参数的类型,但是如果调用时传入的实际参数类型和定义时的指定的类型不同,也不会有任何影响
指定形式参数的类型的作用在于在编写函数的时候编译器会根据指定类型进行代码提示,方便编写代码,仅此而已
提示效果

定义函数的时候可以进行代码注释,当编写调用函数的代码时,解释器会有相应的提示消息出现
提示效果

也可以在help帮助中进行查询,注意查询的名称为__main__.XX

Python中的函数支持嵌套定义,这为闭包的产生奠定了基础(想深入了解Python闭包的同学可以移步Python——闭包与装饰器)
当然,一般情况下是不会单独地在一个函数中定义一个函数,然后在自己对新定义的函数进行调用,而是选择把这个新定义的函数进行返回,交由外部进行调用,即使用闭包
在函数内部定义的函数为一个局部变量
由于函数名本质就是保存着函数对象引用的全局变量,所以Python中的函数对象也可以作为右值参与赋值运算,我们可以通过被赋值的变量调用该函数
当然,函数也可以作为实参传入另一个函数中被调用
如果一个函数没有任何返回值,会返回一个空值None,相当于在函数的最后有一个默认的代码"return None",如果只有一个return,后面没有任何东西返回,那依旧是返回None
- return的两个功能
- 一个功能是返回数据(如果return后面有需要返回处理的数据)
- 另一个功能是提前结束函数代码块的执行
函数可以有多个返回值,这多个返回值会组成一个元组(本质上就是元组构成方式的一种)
函数内部可以直接使用外部的全局变量的数据
但是直接修改全局变量的引用是不被允许的(当然,从异常信息来看,编译器是认为这个局部变量未定义,而进行了使用)
顺带一提,如果在函数中先使用了同名变量,再定义了一个同名的局部变量,也会抛出这个异常
如果在函数内部使用global,就可以借用已经存在的同名全局变量的引用了(相当于全局变量异地登入,这个变量就是外部的同名全局变量,二者是同一个变量),此时就可以修改全局变量保存的引用
在使用global关键字借用全局变量之前,不能再定义一个同名变量,否则会引发异常
由于函数在调用的时候,函数体代码才会执行,所以函数内部的全局变量借用是在函数执行的时候进行的操作
从打印对应对象的引用计数的结果也可以看出
使用global关键字的时候,如果函数之前没有同名的全局变量,则可以实现函数中创建一个全局变量
在闭包中,可以通过global关键字,使用全局变量的数据,而不是使用同名的非局部变量的数据
也可以使用global关键字使得函数成为一个全局变量
函数传参
Python的函数传参只有一种方式,为传址调用,无传值调用,具体来说,就是Python在传参的时候,是将变量保存的对象引用复制一份,交给形参保存
实际参数
- 位置参数
- 位置参数是根据实参位置依次进行参数传递的
- 关键字参数
- 关键字参数是根据形参名称进行指定的参数传递的
- 关键字参数不能写在位置参数之前
- 不能对同一个参数多次赋值,会引发异常
- 同时使用位置参数和关键字参数时,先把所有的位置参数根据实参位置依次进行参数传递后,然后再考虑关键字参数的传递问题,而不是先将关键字参数传递给指定形参,然后再进行位置参数的参数传递
- 序列解包会优先于关键字参数进行赋值(本质可能是在调用传参的时候,由于位置参数必须在关键字参数前面,所以在传参的时候会自动进行位置调整)
形式参数
- 位置参数
- 位置参数是根据实参位置依次进行参数接收的
- 默认值参数
- 默认值参数不需要进行对应的传参,其自身具有默认值,但是当默认值参数与对应传入的参数不同时,还是会进行参数的覆盖(默认值参数的存在可以保证程序功能的向后兼容,即添加新功能之后,不会影响老用户的正常使用)
- 默认值参数不能写在位置参数之前
- 默认值参数赋值语句,是在使用 def 关键字定义函数的时候被执行的,且仅执行这一次,如果每一次都不对默认值形参传入实际参数,相同的"预计算"值将在每次调用时被使用(除非再执行一次def语句,重新进行id赋值),如果此时默认值为列表、字典或类实例等可变对象,就会产生一些奇怪的现象
如果不想在后续调用之间共享默认值,应以如下方式编写函数
- 特殊参数
- 默认情况下,参数可以使用位置参数或关键字关键字的形式传递给 Python 函数。但是为了让代码易读、高效,我们最好可以在函数定义的时候就限制参数的传递方式
- 这样,开发者只需查看函数定义,即可确定某一个参数项是仅可以使用位置参数形式、可以使用位置参数或关键字参数形式,还是仅可以使用关键字参数形式进行参数传递(即仅限关键字参数)
- 仅限关键字参数(Keyword-Only Arguments)是对调用者(也就是函数 arguments)的要求,而非对设计者(也就是 parameter)的要求。 具体来说,在声明函数的时候,没有必要为了显示关键字参数,而为形参给出默认值;但是在使用函数的时候,必须以关键字参数的形式提供数值,而非位置参数
- 不定长参数之个数可变的位置参数
- 使用*定义个数可变的位置参数。个数可变的位置参数可以一次性接收连续的任意多个位置参数,这些实参保存在一个元组中(定义函数时,无法确定用户会传递的位置参数个数时,可以使用)
- 只能有一个个数可变的位置参数
- 个数可变的位置参数可以位于位置参数的后面
- 个数可变的位置参数后的形参仅可以使用关键字参数形式进行参数传递,即为仅限关键字参数(Keyword-Only Arguments)
- 不定长参数之个数可变的关键字参数
- 使用定义个数可变的关键字参数。个数可变的关键字参数可以一次性接收连续的任意多个关键字参数,这些实参保存在一个字典中(定义函数时,无法确定用户会传递的关键字参数个数时,可以使用)
- 只能有一个个数可变的关键字参数
- 不能有其他参数在参数后
- 在关键字参数可以非连续地接收关键字参数(本质可能是函数在调用传参的时候,是同时将所有关键字参数进行传参的,所有只有没有形参与之匹配的关键字参数才会被个数可变的关键字参数接收)
关键字lambda表示匿名函数,因为函数没有名字,所以不必担心函数名冲突。除了匿名,以及形参列表中不能对形参指定类型以及无法使用装饰器进行装饰以外,其他和普通的自定义函数没有区别
可以将匿名函数赋值给一个变量,通过调用此变量来调用lambda函数
对于lambda表达式
- 前半部分(lambda [形参列表] :)即为普通函数的def可执行语句,只会执行一次,而且是在接触到lambda表达式的时候就会执行,同时会把默认值参数进行赋值,
- 后半部分即为普通函数的函数体,只有在调用该函数的时候才会执行里面的代码
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/pythonbc/11894.html