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