一、函数的定义
初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数。自变量x的取值范围叫做这个函数的定义域
例如y=2*x
python中函数定义:函数是逻辑结构化和过程化的一种编程方法。
1 python中函数定义方法: 2 3 def test(x): 4 "The function definitions" 5 x+=1 6 return x 7 8 def:定义函数的关键字 9 test:函数名 10 ():内可定义形参 11 "":文档描述(非必要,但是强烈建议为你的函数添加描述信息) 12 x+=1:泛指代码块或程序处理逻辑 13 return:定义返回值 14 15 16 调用运行:可以带参数也可以不带,根据定义时括号内是否有参数来决定 17 函数名()
例:
#定义函数 def test(x): y = 2 * x + 1 return y #调用函数 print(test) test(3) ##调用函数但是return的值没有接收,返回的是test函数的内存地址 a = test(2) ##使用变量a接收函数的返回值 print(a)
输出:
注意:当函数出现重名时,调用时后边的函数会覆盖掉之前的函数,因为python语言从上到下依次解释执行
return 不能出现多个,代码执行时碰到第一个return就会结束
例:
#定义函数 def test(x): y = 2 * x + 1 return y def test( ): x = 2 y = x + 1 return y #调用函数 a = test() #b = test(2) ##会报错 print(a)
二、为什么要有函数
通过下面实现同一功能的两块代码对比,就可以看出在某些合适的生产场景下使用函数的好处:
代码1: while True: if cpu利用率 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 硬盘使用空间 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 内存占用 > 80%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 代码2: def 发送邮件(内容) #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True: if cpu利用率 > 90%: 发送邮件('CPU报警') if 硬盘使用空间 > 90%: 发送邮件('硬盘报警') if 内存占用 > 80%: 发送邮件('内存报警')
使用函数的好处:
1.代码重用(减少冗余,提高代码的有效性)
2.保持一致性,易维护
3.可扩展性
三、函数和过程
过程定义:过程就是简单特殊没有返回值的函数,即没有return,返回值为None
这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情
# 无返回值,为过程 def test01(): msg = 'hello The little green frog' print(msg) # 有返回值,为函数 def test02(): msg = 'hello WuDaLang' print(msg) return msg t1 = test01() t2 = test02() print ('from test01 return is %s' %t1) ##返回值为None print ('from test02 return is %s' %t2)
输出:
总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None,
所以在python中即便是过程也可以算作函数。
def test01(): pass def test02(): return 0 def test03(): return 0,10,'hello',['alex','lb'],{'WuDaLang':'lb'} t1=test01() t2=test02() t3=test03() print('from test01 return is [%s]: ' %type(t1),t1) print('from test02 return is [%s]: ' %type(t2),t2) print('from test03 return is [%s]: ' %type(t3),t3) ##当返回值为多个时,会将这几个值组成一个元组返回
输出:
总结:
返回值数=0:返回None
返回值数=1:返回object
返回值数>1:返回tuple
四、函数中的参数
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元,也就是说形参不占用内存空间(变量亦是如此,不会占用内存空间,只有真正的数据类型才会占用内存空间)。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)
- 位置参数(必须一一对应)
def test(x,y,z): print(x) print(y) print(z) test(1,2) ##x=1,y=2,没有给z赋值,会报错
输出:
- 关键字参数(位置不用固定,但是个数不能少)
def test(x,y,z): print(x) print(y) print(z) test(y=1,z=2,x=5)
输出:
- 位置参数与关键字参数的混合使用(位置参数必须在关键字参数的左边)
def test(x,y,z): print(x) print(y) print(z) # test(3,y=5,8) ##会报错
# test(3,5,8,y=4) ##也会报错,因为不可以重复赋值给某一形参 # test(3,8,y=5) ##也会报错,执行时默认将3赋值给x,将8赋值给y test(3,8,z=5) ##正常执行
4.默认参数
默认参数:在调用时如果不给它赋值则它等于默认值,默认值可以为任何类型的值
def handle(x,y=None): print(x,type(x)) print(y) handle('12ed') ##不给默认参数赋值的时候,默认参数等于默认值 handle(2,'hello')
输出:
5.参数组
非固定长度的参数(后期可以扩展):
* 列表、元组
** 字典
- 列表、元组
def test(x,*args): ##*代表非固定长度的参数值 print(x) print(args) # print(args[1]) ##输出为空元组 test(1,12,4,5,'ds') ##将第一个实参传给第一个形参,后边所有的实参组合成元组传给第二个形参,该例子中实参可以为任意数据类型 test(1) ##不给第二个形参传值也可以,但需取掉函数中的print(args[1]),否则会报错 test(1,['1',23,2,2]) test(1,*['x',12,'q21']) ##*表示将该列表中的元素遍历,第一种调用函数的方法类似,元组也是如此
输出:
- 字典
def test(x,**kwargs): print(x) print(kwargs) test(1,y=2,z=3) ##将第一个实参后的所有实参组合成一个字典赋值给第二个形参,注意只能使用key=value的形式赋值 #三个混合使用时,只能使用下面的顺序 # def test1(x,*args,**kwargs):
五、局部变量与全局变量
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
name = 'lee' ##全局变量:顶格写,全局生效 ##局部变量:在子程序中定义的变量,在该子程序之外的部分不生效,例如def自定义函数中 def change_name(): first_name = 'hello' # print('my name:',name) ##全局变量在子程序中也生效,但是当在子函数中如果对该变量重新赋值时,调用该变量的代码块只能出现在其后,否则会报错 print(first_name) name = 'mike' print(name) change_name() ##调用函数时,如果使用了变量,执行时会默认先在函数内层(即局部变量)找,如果没有再在外部(即全局变量)找
print(name) ##局部变量无效,只有全局变量生效
输出:
name = 'lee' ##全局变量:顶格写,全局生效 ##局部变量:在子程序中定义的变量,在该子程序之外的部分不生效,例如def自定义函数中 def change_name(): global name ##将全局变量引入函数内部,在函数内如果重新定义变量的话就是改变的全局变量,注意如果使用global并且重新对变量赋值,则在函数内global之前不能调用全局变量 name = 'mike' print(name) change_name() print(name) ##局部变量无效,只有全局变量生效
注意:如果函数中没有对变量重新赋值(即指定与全局变量名称相同的局部变量),但局部变量是可变对象(如列表等),可以在函数中直接使用该可变对象的内置方法(如列表的.append方法)
输出: