第四篇 函数基础
第四篇 函数基础
一 函数的定义
函数就是具备某一功能的工具,事先将工具准备好就是函数的定义,遇到应用场景拿来就用就是函数的调用,
函数作用
- 解决程序冗长
- 解决程序的扩展性差
- 解决程序的可读性差
定义函数:
函数的使用必须遵循'先定义,后调用'的原则.(函数定义阶段,只检测语法,不执行函数体系代码)
定义函数的语法
def 函数名(参数1 参数2...):
"""文档描述"""
函数体
return 值
- def:定义函数的关键字;
- 函数名:函数名指向函数内存地址,是对函数体代码的引用.函数名应该反映出函数的功能
- 括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;
- 冒号:括号后要加冒号,然后在下一行开始缩进写函数体的代码;
- """文档描述""":描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;
- 函数体:由语句和表达式组成;
- return值:定义函数的返回值,return是可有可无的.
- pass:函数体为pass代表什么都不做,称为空函数,用于编写程序初搭建体系结构.
二 函数定义的三种形式
无参函数:
定义函数时参数是函数体接收外部传值的一种媒介,其实就是一个变量名.在函数阶段括号内没有参数,称之为无参函数.需要注意的是:定义时无参,意味着调用函数时也是需要传入参数.
如果函数体代码逻辑不需要依赖外部传入的值,必须得定义成无参函数.
有参函数
在函数定义阶段括号内有参数,称之为有参函数.需要注意的是:定义时有参,意味着调用时也必须传入参数.
如果函数体代码逻辑需要依赖外部传入的值,必须得定义成有参函数.
空函数
当你只知道你需要实现某个功能,但不知道如何用代码实现时.可以暂时写个空函数,然后先实现其他功能.(pass)
三 函数返回值
return:
return是一个函数结束的标志,函数内可以有多个return,只要执行到return,函数就会执行
return的返回值可以返回任意数据类型
return的返回值无个数限制,既可以使用逗号隔开返回多个值
- 0个:返回none
- 1个:返回值是该值本身
- 多个:返回值是元组
四 函数调用
上面就讲到了函数调用.函数名(...)即调用函数,会执行函数体代码,直到碰到return或者执行完函数体内所有代码结束.
函数运行完毕所有代码,如果函数体不写return,则会返回none
函数调用的三种形式
def max_self(x, y):
if x>y:
return x
eles:
return y
#1.
max_self(1,2)
#2
res = max_self(1,2)*12
#3
max_self(max_self(20000,30000),40000)
五 函数的参数
函数分为形参实参:
形参: 即在定义函数时,括号内声明的参数,形参本质就是一个变量名,用来接受外部传来的值.
实参:即在调用函数时,括号内传入的值,值可以是常量,变量,表达式或三则的组合.
在调用有参函数时,实参(值)会赋值给形参(变量名).在python中,变量名与值只是单纯的绑定关系,而对于函数来来说,这种绑定关系只在函数调用时生效,在调用时结束后解除.
位置参数
位置参数指的是按顺序定义的参数,需要从两个角度去看;
位置形参:
在定义函数时,按照从左到右的顺序依次定义形参,称为位置形参,.
凡是按照这种形式定义的形参都必须被传值.
位置实参:
在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参,
凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应.
关键字参数
在调用函数时,按照key= value的形式为指定的参数传值,称之为关键字实参
特点:可以打破位置的限制,但仍能为指定的形参赋值.
注意:
- 可以混用位置实参和关键字实参,但是位置实参必须在关键字实参的左边
- 可以混用位置实参和关键字实参,但不能对一个形参重复赋值.
默认形参
特点:在定义阶段就已经被赋值,意味着在调用时可以不用为其赋值.
注意:
- 位置形参必须放在默认形参的左边.
- 默认形参的值旨在定义阶段赋值一次,也就是说默认参数的值在函数定义阶段就已经固定了.
- 默认参数的值通常应该是不可变类型.
小结
实参的应用:取决于个人习惯
形参的应用:
- 大多数情况的调用值一样,就应该将该参数定义成位置形参
- 大多数情况的调用值一样,就应该将该参数定义成默认形参
六 可变长参数
可变长参数:
指的是在调用函数时,传入的参数个数可以不固定;调用函数时,传值的方式无非有两种,一种是位置实参,另一种是关键字实参,因此形参也必须的有两种解决方法,以此来分别接收溢出的位置实参(*)与关键字实参(**)
可变长形参之*:
形参中的*会将溢出的位置实参全部接收,然后存储元组的形式,然后元组赋值给*的参数.需要注意的是:*后的参数名约定俗成为args.
可变长实参之*:
实参中的*,*会将*后参数的值循环取出,打散成位置实参.以后但凡碰到实参中带*的,他就是位置实参,应该马上打散成位置实参去看.
可变长形参之**:
形参中的**会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给**的参数.需要注意的是:**后的参数名约定俗成为kwargs.
可变长实参之**:
实参中的**,**会将**后参数的值循环取出,打散成关键字实参.以后但凡碰到实参中带**的,他就是关键字实参,应该马上打散成关键字实参去看.
==命名关键字形参==:
在函数定义阶段,*后面的参数都是命名关键字参数
特点:在传值时,必须按照key=value的方式传值,并且key 必须命名关键字参数的指定的参数名.
七 函数对象的四大功能
引用
x = 'hello nick' y = x f = func print(f)
当作参数传给一个函数
len(x) def foo(m): m() foo(func)
可以当作函数的返回值
def foo(x): return x res = foo(func) print(res) res()
可以当作容器类型的元素
1 = [x] function_list = [func] function_list[0]()
八 函数嵌套
函数的嵌套定义:函数内部定义的函数,无法在函数外部使用内部定义的函数.
打比方:也就是说把一堆工具丢进工具箱内,之后想要获得某个工具,直接从工具箱中获取就行了.
from math import pi
def circle(radius, action='area'):
def area():
return pi * (radius**2)
def perimeter():
return 2*pi*radius
if action == 'area':
return area()
else:
return perimeter()
print(f"circle(10):{circle(10)}")
print(f"circle(10),action='perimeter'):
{circle(10,action='perimeter')}")
九 名称空间和作用域
函数内部定义的函数,无法在函数外部使用内部定义的函数;学习这一节你就会知道为什么出现这种情况.
名称空间
名称空间定义:内存中有一块内存存储变量名与变量间的绑定关系的空间,而这个空间称为名称空间.
内置名称空间:
内置名称空间:存放python解释器自带的名字,如int,float,len
生命周期:在解释器启动时生效,在解释器关闭时失效.
全局名称空间:
除了内置和局部的名字之外,其余都是存放在全局名称空间,如下代码中的x,func,l,z
生命周期:在文件执行时生效,在文件执行结束后失效
局部名称空间(局部名称空间):
局部名称空间:用于存放函数调用期间函数体产生的名字,如下面代码的f2
生命周期:在文件执行时函数调用期间时生效,在函数执行结束后失效
加载顺序:
由于.py文件是python解释器打开中的内置名称空间加载结束后,文件才开始打开,这个时候才会产生全局名称空间,但文件内有某一个函数被调用的时候,才会开始产生局部名称空间,因此名称空间的加载顺序为:内置-->全局-->局部
查找顺序:
由于名称空间是用来存放变量名与值之间的绑定关系的,所以但凡要查找名字,一定是从三者之一找到,查找顺序为:
从当前的所在位置开始查找,如果当前所在的位置为局部名称空间,则查找顺序为:局部-->全局-->内置
作用域
域指的是区域,作用域即作用的区域.
全局作用域:
全局有效,全局存活,包含内置名称空间和全局名称空间.
局部作用域:
局部有小,临时存储,只包含局部名称空间.
注意点:
作用域关系在函数定义阶段就固定死了,与函数的调用无关.
函数对象+作用域应用
def f1(): def inner(): print('from inner') return inner f =f1() def bar(): d() bar() #from inner
==注意点==
- 在局部想要修改全局的可变类型,不需要任何生命,可以直接修改.
- 在局部如果想要修改全局的不可变类型,需要借助global声明,声明为全局的变量,即可直接修改.