一. 创建函数
1.1 定义
函数: 指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。
语法:
def函数名([形参]): 函数过程函数名([实参])#调用函数
举例:
defsayhi():#函数名
print('hello')sayhi()#如果不加括号只是表示该函数内存地址
1.1.1 函数特性
减少重复代码
使程序变得可扩展
使程序变得易维护
1.2 文档化函数
如果想要给函数写文档,让其他使用该函数的人能理解的话,可以加入注释,方法有2中:
#开头
在def语句后面(以及在模块或者类的开头)直接写上字符串
如果在函数的看透写下字符串,它就会作为函数的一部分进行存储,称为文档字符串
defsquare(x):
'calculates the square of number x'returnx*x
文档字符串可以按如下方式访问:
defsquare(x):
'calculates the square of number x'returnx*xprint(square.__doc__)
#输出
calculates the square of number x
1.3 并非真正函数的函数
python的有些函数并不返回任何东西,但是python的函数就是函数:没有return语句或者虽然有return语句后面没有跟任何值的函数不返回值
其实python所有的函数都返回了东西:当不需要他们返回任何值的时候,他们就返回None
警告
千万不要被默认行为所迷惑。如果在if语句内返回值,那么要确保其他分支也有返回值,这样一来当调用者期待一个序列的时候,就不会意外的返回None
二. 函数参数
参数可以让你的函数更加灵活,不只能做死的动作,还可以根据调用时传参的不同来决定函数内部的执行过程
2.1 形参变量
只有在被调用的时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。
2.2 实参
可以是常量、变量、表达式、函数、字典、列表等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值。
a,b=5,8defcalc(x,y):#x,y为形参res=x**y
returnresc=calc(a,b)#a,b为实参
print(c)
2.3 关键参数和默认参数
之前所使用的参数都叫位置参数,因为他们的位置很重要,甚至比他们的名字更重要。这里学的内容可以回避位置问题。
例题: 考虑下面两个函数:
defhello_1(greeting,name):
print('%s,%s'%(greeting,name))
defhello_2(name,greeting):
print('%s,%s'%(name,greeting))
两个代码所实现的是完全一样的功能,只是参数顺序反过来了:
hello_1('hello','world')hello,world#输出
hello_2('hello','world')hello,world#输出
有些时候(尤其是参数很多的时候),参数的顺序是很难记住的。为了让事情简单些,可以提供参数的名字:
这样一来,顺序就完全没有影响了,但参数名和值一定要对应
hello_1(name='hello',greeting='world')hello,world#输出
关键字参数
私用参数名提供的参数叫做关键字参数,主要作用在于可以明确每个参数的作用,避免弄乱了参数的顺序。
关键字参数最厉害的地方在于可以在函数中给参数提供默认值
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),但是记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定的参数)之后
defstu_register(name,age,country,course):
print("----注册学生信息----")
print("姓名:",name)
print("age:",age)
print("国籍:",country)
print("课程:",course)stu_register("王二",22,"CN","python_devops")stu_register("张三",21,"CN","linux")
可以这样调用
stu_register("王二",course="python_devops",age=22,country='JP')
但是不可以这样
stu_register(course="python_devops","王二",age=22,country='JP')
也不可以这样
stu_register("王二",22,age=22,course="python_devops")
默认参数
当参数具有默认值的时候,调用的时候就不用提供参数了!可以不提供、提供一些或提供所有的参数:
注意
默认参数应该在参数的后面
如果要更改默认参数,直接在后面填写需要更改的值
例题:如何将country默认为CN
defstu_register(name,age,course,country="CN"):
print("----注册学生信息----")
print("姓名:",name)
print("age:",age)
print("国籍:",country)
print("课程:",course)stu_register("王二",22,"python_devops")stu_register("张三",21,"linux",'Korean')
2.4 收集参数
收集参数又叫做非固定参数
带* 参数
参数前带*号的参数将所有值放在同一个元组中。讲这些值收集起来,然后使用。
一般用*args
带*的参数不能放在前面
带* 参数举例
单纯重复输入普通参数:
#报警,1个运维人员
defsend_alert(msg,user):
print(msg)
print(user)#报警,10个运维人员
send_alert("请注意,内存过满!","alex")send_alert("请注意,内存过满!","Jack")
带* 参数与普通参数联合使用
带* 参数收集其余的位置参数。如果不提供任何收集元素,收集参数返回的是空元组。
优化代码--方式一
defsend_alert(msg,*user):#users为一个元组print(msg)
print(user)send_alert("请注意,内存过满!","alex","Jack","Junee")
#输出
请注意,内存过满!(alex Jack Junee)
带* 参数与列表联合使用
优化代码--方式二 []-->*[] = ([])-->()
显示出来为列表内的元素按顺序依次执行函数
defsend_alert(msg,*users):#users为一个元组foruinusers:
print(msg,u)send_alert("请注意,内存过满!",*["alex","Jack","Junee"])
#输出
请注意,内存过满! alex请注意,内存过满! Jack请注意,内存过满! Junee
带* 参数与关键字参数联合使用
当带 * 参数与关键字参数联合使用时候,会报错,需要另外一个能处理关键字参数的“收集”操作带的参数**。
defsend_alert(msg,*user):#users为一个元组print(msg)
print(user)send_alert("请注意,内存过满!",todo='请处理')
#输出
TypeError: send_alert() got an unexpected keyword argument'user'
带** 参数
带** 参数输入值为关键字参数
带** 参数返回的是字典而不是元组
defsend_alert(msg,**user):#users为一个元组print(msg)
print(user)send_alert("请注意,内存过满!",todo='请处理')
#输出
请注意,内存过满!{'todo':'请处理'}
带** 参数举例
例题1
deffunc(name,*args,**kwargs):
print(name,args,kwargs)func("Alex",22,"tesla","500W")
#输出
lex (22,'tesla','500W') {}
例题2
deffunc(name,*args,**kwargs):
print(name,args,kwargs)func("Alex",22,"tesla","500W",addr="山东",num=13818)
#输出
Alex (22,'tesla','500W') {'addr':'山东','num':13818}
例题3
deffunc(name,*args,**kwargs):
·print(name,args,kwargs)d={"degree":"primary school"}func("peiqi",d)func("peiqi",*d)func("peiqi",**d)#输出peiqi ({'degree':'primary school'},) {}peiqi ('degree',) {}peiqi () {'degree':'primary school'}
2.5 参数收集的逆过程
如何将参数收集为元组和字典已经讨论过了,但是事实上,如果使用 * 和 ** 的话,也可以执行相反的操作。
带* 参数收集逆过程举例
那么参数收集的逆过程是什么样?假设有如下函数:
defadd(x,y):returnx+y
比如说有个包含由两个要相加的数字组成的元组:
params=(1,2)
这个过程多少有点像我们上一节中介绍的方法的逆过程。不是要收集参数,而是要分配它们在“另一端”。
使用* 运算符就简单了---不过是在调用而不是在定义时使用:
add(*params)
#输出
3
带** 参数收集逆过程举例
defhello_1(greeting,name):
print('%s,%s'%(greeting,name))params={'greeting':"Sir","name":"well met!"}hello_1(**params)
#输出
Sir,well met!
在定义或者调用函数时使用*(或者**)仅传递元祖或字典,所以可能没遇到什么麻烦:
defwith_stars(**kwds):
print(kwds['name'],'is',kwds['age'],'years old.')
defwithout_stars(kwds):
print(kwds['name'],'is',kwds['age'],'years old.')
args={'name':'Mr,Gumby','age':42}
with_stars(**args)without_stars(args)
#输出
Mr,Gumbyis42years old.Mr,Gumbyis42years old.
可以看出,在with_stars中,在定义和调用函数时候都是用了*
但是在without_stars中两处都没有用,但是得到了同样的效果
所以*只在定义函数(允许使用不定数目的参数)或者调用(‘分割’字典或序列)时才有用
领取专属 10元无门槛券
私享最新 技术干货