python学习——函数
一、在python的世界里什么是函数:
答:函数通常是用来实现某一个功能二被封装成的一个对象,是用来实现代码复用的常用方式
现在有一个需求,假如你在不知道len()方法的情况下,要你计算字符串‘hello world’的长度,你是这样来实现的:
1 s1 = 'hello world' 2 length = 0 3 for i in s1: 4 length += 1 5 6 print(length)
very good,现在需求又变了,让你又计算字符串‘hello python’的长度,ok,没问题,请看下面 👇:
1 length = 0 2 s2 = 'hello python' 3 for i in s2: 4 length += 1 5 6 print(length)
好了,你同样也实现了计算‘hello python’ 这个字符串的长度,那你是否会有疑问呢? 如果我有很多像以上的这些字符串(假如有10000个),那我计算每个字符串的长度都要这样写吗?是否有某一个功能来完美的实现这个问题呢?ok,再往下看。
二、函数的定义与调用
例2:为了实现计算字符串而我定义了这样一个函数
1 def my_length(): 2 s1 = 'hello world' 3 length = 0 4 for i in s1: 5 length += 1 6 print(length)
以上是实现计算字符串‘helloworld’的长度的代码。看来之后你就想原来这样就可以拿到字符串长度的结果了。哈哈,你太天真了,当你运行代码的时候你会发现什么都没有,why?因为你根本就没有调用它。那怎样调用函数呢?是这样的:
my_length()
是不是很简单,对,就是这么简单。
例3:函数的定义与调用
1 #函数定义 2 def my_length(): 3 """计算字符串的长度""" 4 s1 = 'hello world' 5 length = 0 6 for i in s1: 7 length += 1 8 print(length) 9 10 #函数调用 11 my_lengh()
总结一:
定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
def 是固定的, ‘不能变’*3,必须是连续的def三个字母,不能分开。。。它们要相亲相爱的在一起。空格 为了将def关键字和函数名分开,必须空(四声),当然你可以空2格、3格或者你想空多少都行,但正常人还是空1格。
函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能
括号:是必须加的,先别问为啥要有括号,总之加上括号就对了!
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在定义函数下面的第一行。以增强代码的可读性。
调用:就是 函数名() 要记得加上括号,ok!
三、函数的返回值
刚刚我们就写了一个函数,这个函数可以帮助我们计算字符串的长度,并且把结果打印出来。但是,这和我们的len方法还不是太一样。哪里不一样呢?以前我们调用len方法会得到一个值,我们必须用一个变量来接收这个值,然后就可以打印出我们的结果了。是这样的:
1 str_length = len('hello world') 2 3 print(str_length)
既然是这样,那函数是不是也能实现呢?来,试一下,看下面:
1 #函数定义
2 def my_length():
3 """计算字符串的长度"""
4 s1 = 'hello python'
5 length = 0
6 for i in s1:
7 length += 1
8 return length
9
10 #函数调用
11 str_length = my_length()
12 print(str_length)
所有我们只要在函数后面加上return这个关键字之后我们就可以拿到函数返回的结果了,接下来我们研究一下return这个关键字的用法。
return关键字的作用:
return 是一个关键字,在pycharm里,你会看到它变成蓝色了。你必须一字不差的把这个单词给背下来。
这个词翻译过来就是“返回”,所以我们管写在return后面的值叫“返回值”
要研究返回值,我们还要知道返回值有几种情况:分别是没有返回值、返回一个值、返回多个值
1.没有返回值
不写return的情况下,会默认返回一个None:我们写的第一个函数,就没有写return,这就是没有返回值的一种情况。
1 #函数定义 2 def my_length(): 3 """计算字符串s1的长度""" 4 s1 = 'hello python' 5 length = 0 6 for i in s1: 7 length += 1 8 print(length) 9 10 #函数调用 11 str_length = my_length() 12 print('str_length: {}'.format(str_length)) 13 14 #运行结果:12 15 # str_length: None
运行结果里面的12确实是‘hello python’的长度,但那是函数内打印的,二调用时的my_length为None。
只写return,后面不写其他内容,也会返回None,有的同学会奇怪,既然没有要返回的值,完全可以不写return,为什么还要写个return呢?这里我们要说一下return的其他用法,就是一旦遇到return,结束整个函数。
1 def my_length(): 2 """计算字符串s1的长度""" 3 s1 = 'hello python' 4 length = 0 5 for i in s1: 6 length += 1 7 return 8 9 #函数调用 10 str_length = my_length() 11 print('str_length: {}'.format(str_length)) 12 13 #运行结果:str_length: None
1 #函数定义 2 def my_length(): 3 """计算字符串s1的长度""" 4 s1 = 'hello python' 5 length = 0 6 for i in s1: 7 length += 1 8 print(length) 9 return 10 print(length) 11 12 #函数调用 13 str_length = my_length() 14 print('str_length: {}'.format(str_length)) 15 16 #运行结果: 12 17 # str_length: None
和上面一样,同样返回None,而且后面的print语句不会执行,所有一定要记住当函数遇见return时函数就结束了。当然,return None和上面的两种情况一样,我们一般不这样写。
2.返回一个值
刚刚我们已经写过一个返回一个值的情况,只需在return后面写上要返回的内容即可。
1 def my_length(): 2 """计算字符串s1的长度""" 3 s1 = 'hello python' 4 length = 0 5 for i in s1: 6 length += 1 7 return length 8 9 #函数调用 10 str_length = my_length() 11 print('str_length: {}'.format(str_length)) 12 13 #运行结果:str_length: 12
注意:return和返回值之间一定要有一个空格,可以反回任意数据类型的值
3.返回多个值
可以返回任意多个、任意数据类型的值
1 #函数定义 2 def func1(): 3 """返回多个值""" 4 return 1,2,3,4 5 6 def func2(): 7 """返回多个任意数据类型的值""" 8 return 1,['1','2',(1,2),3],2,3 9 10 #函数调用 11 ret1 = func1() 12 print(ret1) 13 ret2 = func2() 14 print(ret2) 15 16 #运行结果: (1, 2, 3, 4) 17 # (1, ['1', '2', (1, 2), 3], 2, 3)
如果聪明的你仔细看,你会发现,返回的所有类型的值被组成了一个元组的形式返回。
1 #函数定义
2 def func1():
3 """返回多个任意数据类型的值"""
4 return 1,['1','2',(1,2),3],2,3
5
6 #函数调用,返回多个值,用一个变量接收
7 ret1 = func1()
8 print(ret1)
9 #函数调用,返回多个值,用多个变量接收
10 a,b,c,d = func1()
11 print('a={} b={} c={} d={}'.format(a,b,c,d))
12
13 #运行结果: (1, ['1', '2', (1, 2), 3], 2, 3)
14 # a=1 b=['1', '2', (1, 2), 3] c=2 d=3
为什么会这样,其实这是python的序列解包
四、函数的参数
现在,我们已经把函数返回值相关的事情研究清楚了,我们自己已经完成了一个可以返回字符串长度的函数。但是现在这个函数还是不完美,之前我们使用len函数的时候得是length = len("hello world"),这样我可以想计算谁就计算谁的长度。但是现在我们写的这个函数,只能计算一个“hello world”的长度,换一个字符串好像就是不行了。这可怎么办?
1 #函数定义
2 def my_length(s1):
3 """计算字符串s1的长度"""
4 length = 0
5 for i in s1:
6 length += 1
7 return length
8
9 #函数调用
10 str_length = my_length('hello python')
11 print('str_length: {}'.format(str_length))
12 # 运行结果: str_length: 12
我们告诉mylen函数要计算的字符串是谁,这个过程就叫做 传递参数,简称传参,我们调用函数时传递的这个“hello world”和定义函数时的s1就是参数。
实参与形参
参数还有分别:
我们调用函数时传递的这个“hello world”被称为实际参数,因为这个是实际的要交给函数的内容,简称实参。
定义函数时的s1,只是一个变量的名字,被称为形式参数,因为在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。
传递多个参数
参数可以传递多个,多个参数之间用逗号分割。
1 def bigger(x,y): 2 """比较两个数的大小,返回较大的数""" 3 return x if x > y else y 4 5 ret = bigger(10,20) 6 print(ret)
机智的你可能会问了,return后面哪一行到底是什么鬼?然后机制Plus的我来告诉你,这是三元运算,三元运算是为了在开发过程中减少代码量而存在的,运用方式如下:
1 ret = x if x > y else y 2 3 # 变量名 = 条件为True的返回值 if 条件 else 条件为False的返回值
**********注意:这是一个固定的表达式,if 和else都必须有,而且还要加一个变量名来接收返回的结果************
也正是因为需要传递多个参数、可以传递多个参数,才会有了后面这一系列参数相关的故事。。。
位置参数
站在实参角度
1.按照位置传值
1 def bigger(x,y): #此时,x=10,y=20 2 """比较两个数的大小,返回较大的数""" 3 return x if x > y else y 4 5 ret = bigger(10,20) 6 print(ret)
2.按照关键字传值
1 def bigger(x,y): #此时,x=20,y=10 2 """比较两个数的大小,返回较大的数""" 3 return x if x > y else y 4 5 ret = bigger(y = 10,x = 20) 6 print(ret)
3.位置和关键字混用
1 def bigger(x,y): #此时,x=10,y=20 2 """比较两个数的大小,返回较大的数""" 3 return x if x > y else y 4 5 ret = bigger(10,y = 20) 6 print(ret)
正确使用方法
1.1 位置参数必须在关键字参数的前面
1.2 对于一个参数只能赋值一次
站在形参角度
1.位置参数必须传值
1 def bigger(x,y): #此时,x=10,y=20 2 """比较两个数的大小,返回较大的数""" 3 return x if x > y else y 4 5 ret = bigger() #没有给形参传值 6 print(ret) 7 8 #结果:Traceback (most recent call last): 9 # File "D:/Python文件/python学习/函数学习.py", line 91, in <module> 10 # ret = bigger() 11 # TypeError: bigger() missing 2 required positional arguments: 'x' and 'y'
这时程序会报错,说少了两个参数 x 和 y
默认参数
正确使用方法
1.为什么要使用默认参数:为了把变化较小的值设置成默认参数
2.默认参数的定义
1 def student_info(name,sex = 'biautiful girl'): 2 print(name,sex) 3 4 student_info('luoshengyun') 5 student_info('liulonghai','handsome boy') 6 7 #运行结果: luoshengyun biautiful girl 8 # liulonghai handsome boy
3.参数陷阱:默认参数是一个可变数据类型
1 def defult_lis(a,l=[]): 2 l.append(a) 3 print(l) 4 5 defult_lis('liulonghai') 6 defult_lis('luoshengyun') 7 defult_lis('luodehua') 8 defult_lis('liuyonggui') 9 10 # 运行结果:['liulonghai'] 11 # ['liulonghai', 'luoshengyun'] 12 # ['liulonghai', 'luoshengyun', 'luodehua'] 13 # ['liulonghai', 'luoshengyun', 'luodehua', 'liuyonggui']
这就是一个陷阱,我们一定要注意,按理说我们每一次调用都应该得到一个独立的列表,而且每次列表里面的元素都只有一个,但是python就是不干,它就要把你加入的元素都放在同一个列表里面,哼哼,你能奈我何?
动态参数
按位置传值多余的参数都由args统一接收,保存成一个元组的形式
1 def my_sum(*args): 2 the_sum = 0 3 for i in args: 4 the_sum += i 5 6 return the_sum 7 8 the_sum = my_sum(1,2,3,4,5) 9 print(the_sum) 10 11 #运行结果: 15
1 def student_info(**kwargs): 2 print(kwargs) 3 print(kwargs['name'],kwargs['sex']) 4 5 student_info(name='liulonghai',sex='male') 6 7 #运行结果:{'name': 'liulonghai', 'sex': 'male'} 8 # liulonghai male
**********在实际开发中,我们终将会用到它的***********
总结二:函数定义与调用及相关参数的总结:
1 # 1.函数的定义:def 关键字开头,空格之后接函数名和圆括号(); 2 # 2.参数:圆括号用来接收参数。如果传入多个参数,参数之间用逗号分割。 3 # 参数可以定义多个,也可以不定义。 4 # 参数有很多种,如果涉及到多种参数的定义,应始终遵循 位置参数、*args、默认参数、**kwargs顺序定义 5 # 若上述参数有缺少,其他参数依旧遵循以上顺序。 6 # 3.注释:函数的第一行语句应该添加注释,这是一个好程序猿应该有的素质。 7 # 4.函数体:函数内容以冒号开始,并且通过tab键进行缩进(默认缩进4个字符) 8 # 5.返回值:return [表达式] 结束函数执行。不带return关键字的函数python默认返回None 9 # 6.函数的表达式如下: 10 # def 函数名(参数1,参数2,*args,默认参数,**kwargs): 11 # """被注释的内容""" 12 # 函数体 13 # ... 14 # return 返回值
函数调用的总结:
1 # 1.函数名() 2 # 函数后面加圆括号即为函数调用。 3 # 2.参数: 4 # 圆括号用来接收多个参数。 5 # 若传入多个值 6 # 应先按位置传值,再按关键字传值 7 # 具体的传入顺序应按照函数定义的参数情况相同 8 # 3.返回值: 9 # 如果函数有返回值,还应该定义一个 变量名 来接收返回结果 10 # 如果函数返回多个值,也可以用多个变量来接收,且变量数应和返回数相同
参数总结:
五、函数相关作业
1.写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
1 def func(lst_tup): 2 return lst_tup[1::2] 3 4 print(func([1,2,3,4,5]))
2.写函数,判断用户传入的值(字符串,列表,元组)长度是否大于5。
1 def func(s_l_t): 2 return len(s_l_t) > 5 3 4 print(func('hello python')) 5 print(func((1,2,3))) 6 print(func(([1,2,3,4,5,6])))
3.写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
1 def func(lst): 2 if len(lst) > 2: 3 return lst[:2:] 4 5 print(func(['a','b','c',1,2,3]))
4.写函数,计算传入字符串中[数字],[字母],[空格]以及[其他]的个数,并返回结果。
1 def func(str): 2 # number_digit = 0 3 # number_alpha = 0 4 # number_space = 0 5 # number_other = 0 6 number_digit, number_alpha, number_space, number_other = 0,0,0,0 7 for i in str: 8 if i.isdigit(): 9 number_digit += 1 10 elif i.isalpha(): 11 number_alpha += 1 12 elif i.isspace(): 13 number_space += 1 14 else: 15 number_other += 1 16 return number_digit,number_alpha,number_space,number_other 17 18 print(func('*+ asfjdl23jgsdl fsdj')) 19 20 def func(s): 21 dic = {'number_digit': 0, 'number_alpha': 0, 'number_space': 0, 'number_other': 0} 22 for i in s: 23 if i.isdigit(): 24 dic['number_digit'] += 1 25 elif i.isalpha(): 26 dic['number_alpha'] += 1 27 elif i.isspace(): 28 dic['number_space'] += 1 29 else: 30 dic['number_other'] += 1 31 32 return dic 33 34 print(func('jfl*@&#sd234 fjsd3424 fjsl*&'))
5.写函数,检查用户传入的对象(字符串,列表,元组)的每一个元素是否含有空内容,并返回结果
1 def func(s): 2 if type(s) is str and s: 3 for i in s: 4 if i == ' ': 5 return True 6 elif s and type(s) is list or type(s) is tuple: 7 for i in s: 8 if not i: 9 return True 10 elif not s: 11 return True 12 13 print(func('djfsljfsdlj')) 14 print(func([1,(),2,'a'])) 15 print(func(()))
6.写函数,检查传入字典的每一个value的长度,如果大于2,仅保留前两个长度的内容,并将结果返回给调用者。
1 def func(dic): 2 for k in dic: 3 if len(dic[k]) > 2: 4 dic[k] = dic[k][:2] 5 6 return dic 7 8 print(func({'kk':'kkkk','vvv':[11,22,33,44],'kkk':'vv'}))
7.写函数,用户传入修改的文件名与要修改的内容,执行函数,完成整个文件的批量修改操作。
1 def func(filename,old,new): 2 with open('file',encoding='utf-8',) as fp1,open('{}.txt'.format(filename),'w',encoding='utf-8') as fp2: 3 for line in fp1: 4 if old in line: 5 line = line.replace(old,new) 6 fp2.write(line) 7 import os 8 os.remove(filename) 9 os.rename('{}.txt'.format(filename))