二.函数的基础
一.函数介绍
1.1为什么要用函数
1、组织结构不清晰,可读性差 2、代码冗余 3、管理维护的难度极大,扩展性
1.2什么是函数
具备某一个功能的工具就是程序的中函数 事先准备工具的过程----》函数的定义 拿来就用----》函数的调用 所以函数的使用必须遵循:先定义,再调用
二.定义函数
2.1函数的语法
1、语法 def 函数名(参数1,参数2,...): """ 文档描述 """ 代码1 代码2 代码3 return 值 def:定义函数的关键字 函数名:是用来调用函数的, 函数名的命名必须能反映出函数的功能 文档描述:推荐写上,来增强函数的可读性 代码块:函数的功能实现代码 return:函数的返回值
2.2函数的两个阶段
1.定义阶段
def print_sym(sym,count): #print_sym=<function print_msg at 0x000001B2A33698C8> print(sym*count) def print_msg(msg): print('\033[045m%s\033[0m' %msg)
2.调用阶段
print(print_sym) print_sym('#',30) # print_msg('hello egon')
2.3定义函数的三种类型
1.有参函数 参数是函数体代码用来接收外部传入值的
def max2(x,y): #x=100,=y101 # x=10 # y=3 if x > y: print(x) else: print(y) max2(100,101)
2.无参函数:当函数体的代码逻辑不需要函数的调用者掺入值的情况下,就无参
def func(): print('----------------------') print('---soft run-----------') print('----------------------') def interactive(): name=input('username>>: ').strip() pwd=input('password>>: ').strip() print(name,pwd) interactive() #定义时无参,意味着调用时也无须传入参数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
uname_of_db='egon' pwd_of_db='123' def interactive(): uname_of_inp=input('username>>: ').strip() pwd_of_inp=input('password>>: ').strip() return uname_of_inp,pwd_of_inp def auth(uname,pwd): if uname == uname_of_db and pwd == pwd_of_db: print('登陆成功') else: print('登陆失败') res=interactive() x=res[0] y=res[1] print(x) print(y) auth(x,y)
3.空函数:函数体为pass
def auth(): """ 这是一个认证功能 :return: """ pass def put(): """ 上传功能 :return: """ pass def get(): """ 下载功能 :return: """ pass def ls(): """ list contents :return: """ pass
三.调用函数
3.1调用函数的原则
函数的使用必须遵循:先定义,后调用的原则
注意:没事先定义函数而直接调用,就相当于在引用一个不存在的变量名
定义阶段:在定义阶段只检测语法,不执行函数体代码
调用阶段:根据函数名找到函数的内存地址,然后执行函数体代码
3.2调用函数的三种形式
1.无参
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(): print('from func') func()
2.有参
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def max2(x,y): if x > y: return x else: return y res=max2(10,3) print(res)
3.把函数调用放到表达式里
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def max2(x,y): if x > y: return x else: return y res=max2(10,3)*100 print(res)
4.把函数调用当做另外一个参数传入
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
res=max2(max2(10,3),11) print(res)
四.函数的返回值
4.1什么时候应该有返回值
函数体代码运行完毕后需要有一个返回结果给调用者
4.2返回值有三种形式:
1.没有return,返回值None
def func(): pass res=func() print(res)
2.return后跟一个值,返回该值本身
def func1(): return 1 res=func1() print(res)
3.return可以逗号分隔,返回多个值,会返回一个元组给调用者
def func2(): return 1,2,[1,2,3]#打印得到(1, 2, [1, 2, 3]),加括号或者不加括号返回的都是元祖 res=func2() print(res)
4.3return注意点
1、return返回值的值,没有类型限制 2、return是函数结束的标志,函数内可以写多个return,但 执行一次,函数就立刻结束,并把return后的值作为本次调用的返回值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func3(): print('first') return 1 print('second')#一辈子执行不到 return 2#一辈子执行不到 print('third')#一辈子执行不到 return 3#一辈子执行不到 res=func3() print(res)
五.函数的参数
5.1形参与实参是什么?
形参(形式参数):指的是 在定义函数时,括号内定义的参数,形参其实就变量名 实参(实际参数),指的是 在调用函数时,括号内传入的值,实参其实就变量的值 #x,y是形参 def func(x,y): #x=10,y=11 print(x) print(y) #10,11是实参 func(10,11)
注意
实参值(变量的值)与形参(变量名)的绑定关系只在函数调用时才会生效/绑定
在函数调用结束后就立刻解除绑定
5.2位置参数
1、什么是位置参数?
位置即顺序,位置参参数指的就是按照从左到右的顺序依次定义的参数
相关代码
def foo(x,y,z): print(x,y,z)
分为两种
第一种.在定义函数时,按照位置定义的形参,称为位置形参
注意:位置形参的特性是:在调用函数时必须为其传值,而且多一个不行,少一个也不行
foo(1,2) #TypeError: foo() missing 1 required positional argument: 'z' foo(1,2,3,4) #TypeError: foo() takes 3 positional arguments but 4 were given
第二种.在调用函数时,按照位置定义的实参,称为位置实参
注意:位置实参会与形参一一对应
foo(1,3,2)
5.3什么是关键字参数
在调用函数时,按照key=value的形式定义的实参,称为关键字参数
def foo(x,y,z): #x=1,y=2,z=3 print(x,y,z)
注意: 1、相当于指名道姓地为形参传值,意味着即便是不按照顺序定义,仍然能为指定的参数传值 foo(2,1,3) foo(y=2,x=1,z=3) foo(z=2,aaaa=1) 2\ 在调用函数时,位置实参与关键字实参可以混合使用,但必须 2.1:必须遵循形参的规则 foo(1,z=3,y=2) foo(1,z=3) 2.2:不能为同一个形参重复传值 foo(1,x=1,y=3,z=2) 2.3 位置实参必须放到关键字实参的前面 foo(y=3,z=2,1) ======================================= def foo(x,y,z): #x=1,y=2,z=3 print(x,y,z) 在调用函数时,按照key=value的形式定义的实参,称为关键字参数 注意: 1、相当于指名道姓地为形参传值,意味着即便是不按照顺序定义,仍然能为指定的参数传值 foo(2,1,3) foo(y=2,x=1,z=3) foo(z=2,aaaa=1) 2\ 在调用函数时,位置实参与关键字实参可以混合使用,但必须 2.1:必须遵循形参的规则 foo(1,z=3,y=2) foo(1,z=3) 2.2:不能为同一个形参重复传值 foo(1,x=1,y=3,z=2) 2.3 位置实参必须放到关键字实参的前面 foo(y=3,z=2,1)#这是错误的
5.4什么是默认参数?
在定义阶段,已经为某个形参赋值,那么该形参就称为默认参数
#注意: #1 定义阶段已经有值,意味着调用阶段可以不传值 # def register(name,age,sex='male'): # print(name,age,sex) # # # register('egon',18,) # register('alex',73,'female') # register('wxx',84,) # register('xxx',84) # register('yy',84) #2 位置形参必须在默认参数的前面 # def func(y=1,x): #错误 # pass #3 默认参数的值只在定义阶段赋值一次,也就是说默认参数的值再定义阶段就固定死了 # m=10 # def foo(x,y=m): # print(x,y) # # m='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' # foo(1) # foo(1,11) #4 记住:默认参数的值应该设置为不可变类型 # def register(name,hobby,l=[]): #name='wxx',hobby='play' # l.append(hobby) #l=['play'] # print(name,l) # wxx ['play'] # register('wxx','play') # wxx ['play'] # register('alex','read') # alex ['read'] # register('egon','music') # alex ['music'] # # register('wxx','play',[]) # wxx ['play'] # register('alex','read',[]) # alex ['read'] # register('egon','music',[]) # alex ['music'] def register(name,hobby,l=None): if l is None: l=[] l.append(hobby) #l=['play'] print(name,l) # wxx ['play'] register('wxx','play') # wxx ['play'] register('alex','read') # alex ['read'] register('egon','music') # alex ['music'] # 应用: # 对于经常需要变化的值,需要将对应的形参定义成位置形参 # 对于大多数情况值都一样的情况,需要将对应的形参定义成默认形参
5.5什么是可变长度参数
可变长度指的参数的个数可以不固定,实参有按位置定义的实参和按关键字定义的实参,
所以可变长的实参指的就是按照这两种形式定义的实参个数可以不固定,
然而实参终究是要给形参传值的
所以形参必须有两种对应的解决方案来分别处理以上两种形式可变长度的实参
形参:* **
==========================形参里包含*与**
*会将溢出的位置实参全部接收,然后保存成元组的形式赋值给args
def foo(x,y,z,*args): #args=(4,5,6,7,8) print(x,y,z) print(args) foo(1,2,3,4,5,6,7,8,)
**会将溢出的关键字实参全部接收,然后保存成字典的形式赋值给kwargs
def foo(x,y,z,**kwargs): # kwargs={'c':3,'a':1,'b':2} print(x,y,z) print(kwargs) foo(x=1,y=2,z=3,a=1,b=2,c=3)
==========================实参里包含*与**
def foo(x,y,z,*args): #args=([4,5,6,7,8],) print(x,y,z) print(args) foo(1,2,3,*[4,5,6,7,8]) #foo(1,2,3,4,5,6,7,8) foo(1,2,3,*(4,5,6,7,8)) #foo(1,2,3,4,5,6,7,8) foo(1,2,3,*'hello') #foo(1,2,3,'h','e','l','l','o')
实际应用
六.练习题
1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#题目一 def modify_file(filename,old,new): import os with open(filename,'r',encoding='utf-8') as read_f,\ open('.bak.swap','w',encoding='utf-8') as write_f: for line in read_f: if old in line: line=line.replace(old,new) write_f.write(line) os.remove(filename) os.rename('.bak.swap',filename) modify_file('/Users/jieli/PycharmProjects/爬虫/a.txt','alex','SB')
2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#题目二 def check_str(msg): res={ 'num':0, 'string':0, 'space':0, 'other':0, } for s in msg: if s.isdigit(): res['num']+=1 elif s.isalpha(): res['string']+=1 elif s.isspace(): res['space']+=1 else: res['other']+=1 return res res=check_str('hello name:aSB passowrd:alex3714') print(res)
3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。
4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#题目四 def func1(seq): if len(seq) > 2: seq=seq[0:2] return seq print(func1([1,2,3,4]))
5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#题目五 def func2(seq): return seq[::2] print(func2([1,2,3,4,5,6,7]))
6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
PS:字典中的value只能是字符串或列表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#题目六 def func3(dic): d={} for k,v in dic.items(): if len(v) > 2: d[k]=v[0:2] return d print(func3({'k1':'abcdef','k2':[1,2,3,4],'k3':('a','b','c')}))