一、函数基本使用
1.参数
1.1参数分类
形式参数:简称形参,定义在函数的声明部分,本质是一个没有值的变量,用于接收实参的值
实际参数:简称实参,出现在函数的调用过程中,本质是一个有值的变量或者常量,用于给形参赋值
传参:实参给形参赋值的过程
参数分类:
必需参数
默认参数
关键字参数
不定长参数【可变参数】
基本使用
# 1.必需参数,常用 # 注意1:如果形参是必需参数,调用函数的时候,实参和形参的数量必须保持一致 def func1(a,b): print(a + b) # func1(23) # TypeError: func1() missing 1 required positional argument: 'b' func1(23,5) # 注意2:如果形参是必需参数,根据函数的具体实现需求,实参需要注意类型的问题 # func1(34,'abc') # TypeError: unsupported operand type(s) for +: 'int' and 'str' func1('hello','python') # 2.默认参数 # 注意1:默认参数体现在形参中,实参可以不用给默认参数传参,也可以给默认参数传参,会覆盖掉默认值 # a.练习:封装一个函数,计算任意一个数和5的和 # 使用必需参数的方式封装,缺点:繁琐 def add(num1,num2): print(num1 + num2) add(10,5) add(23,5) add(30,5) # 使用默认参数进行优化 # 注意2:默认参数的出现,可以简化函数的调用 def add(num1,num2=5): print(num1 + num2) add(10) add(23) add(30) add(10,20) # b.默认参数的体现:int(value,base) print(int('110')) print(int('101')) print(int('110',10)) print(int('101',10)) print(int('110',2)) print(int('101',2))
# 练习
def add(num1=0,num2=0):
print(f"{num1} + {num2} = {num1 + num2}")
add()
add(34)
add(23,9)
# 3.关键字参数
# 注意1:关键字参数体现在函数的调用部分,通过关键字参数传参,可以调换参数的顺序
# 注意2:调用函数的时候,如果使用关键字参数,则关键字一定要和形参名称保持一致
def func31(name,age):
print(f"姓名:{name},年龄:{age}")
func31('张三',10)
func31(name='李四',age=20)
# func31(23,'jack') # 姓名:23,年龄:jack
func31(age=23,name='jack')
# 练习1
def add(num1=0,num2=0):
print(f"{num1} + {num2} = {num1 + num2}")
add()
add(34)
add(23,9)
add(num2=66)
# 练习2:
# 注意3:传参过程中,只要保证形参都有值
def func32(name,age=0):
print(f"姓名:{name},年龄:{age}")
func32('aaa')
func32('aaa',34)
func32(name='aaa')
func32(name='aaa',age=6)
func32(age=8,name='aaa')
# 关键字参数在系统函数中体现较多
print(34,45,5,5,sep='*') # 同时体现了默认参数和关键字参数
print(int('110',base=2))
# 4.不定长参数/可变参数
# a. *x:x将会被当做元组处理,实参可以是任意数量的数据
def func41(*num): # 打包
print(num,type(num))
print("*num:",*num) # 拆包
func41() # () <class 'tuple'>
func41('abc') # ('abc',) <class 'tuple'>
func41('abc',45,65,7,8,89,9,True) # ('abc', 45, 65, 7, 8, 89, 9, True) <class 'tuple'>
# b.**x:x将会被当做字典处理,实参必须以key=value的方式传参,key必须是一个标识符
def func42(**num): # 打包
print(num,type(num))
func42()
func42(x=45,y=6,z=67) # {'x': 45, 'y': 6, 'z': 67}
func42(abc='hello')
dict1 = {'a':10,"b":20}
func42(**dict1) # 拆包
# 说明:在实际应用中,*和**可以同时使用
def func(*args,**kwargs):
print(args,kwargs)
func()
func(10,20)
func(10,20,name='zhangsan',age=10)
详细使用
# 1.必需参数 # a.注意1:必需参数传参的时候,一定要注意数量的匹配 def func1(): print("func~~~1111") func1() # func1(34) # TypeError: func1() takes 0 positional arguments but 1 was given # b def func2(a): print("func~~~222",a) # func2() # TypeError: func2() missing 1 required positional argument: 'a' func2(10) func2("abc") # c.注意2:必需参数传参的时候,一定要注意顺序的匹配 def func3(name,age): print(f"姓名:{name},年龄:{age}") # func3(18,"jack") func3("jack",18) # d.注意3:必需参数传参的时候,一定要注意类型的匹配 def func4(name,age): print("姓名:%s,年龄:%d" % (name,age)) # func4("aaa","gahjg") # TypeError: %d format: a number is required, not str func4("张三",10) print("*" * 30) # 2.默认参数 # a.注意1:默认参数体现在形参上 def test1(a,b = 0): # a是一个必需参数,b是一个默认参数 print(a,b,a + b) # 注意2:形参使用默认参数,如果实参给该参数未传参,则使用默认值 test1(3) test1(3,5) # 5会给b重新赋值 # b. def test2(a = 0,b = 0,c = 0): print(a,b,c) test2() test2(2,6) test2(3,4,6) def test3(a,b = 0,c = 0): print(a,b,c) test3(6) def test4(a,b,c = 0): print(a,b,c) test4(6,3) # 注意3:如果形参有多个,可以必需参数和默认参数混合使用,但是在形参中,默认参数靠后书写 # def test4(a,b = 0,c): # SyntaxError: non-default argument follows default argument # print(a,b,c) # test4(6,3) # 注意4:默认参数出现的意义就是为了简化函数的调用 # end默认值为\n print(45) print(60) # print(34,end="*") # 3.关键字参数 # 注意1:关键字参数体现在实参中 def check1(name,age,score): print(f"姓名:{name},年龄:{age},成绩:{score}") # check1("jack",18,100) # check1(18,"jack",100) # 逻辑不通,姓名:18,年龄:jack,成绩:100 # 注意2:使用关键字参数传参可以不用匹配顺序,但是,关键字需要和形参的变量名保持一致 check1(age=18,name="jack",score=100) # 姓名:jack,年龄:18,成绩:100 # check1(age=18,name1="jack",score=100) # TypeError: check1() got an unexpected keyword argument 'name1' check1('aaa',score=88,age=10) check1("bbb",12,score=99) # 注意3:在实参中,关键字参数只能书写在参数的后面 def check2(name,age,score): print(f"姓名:{name},年龄:{age},成绩:{score}") # check2(name="tom",10,66) # SyntaxError: positional argument follows keyword argument # check2(10,66,name="tom") # TypeError: check2() got multiple重复 values for argument 'name' # 注意4:默认参数和关键字参数可以结合使用 def check3(name,age,score=0): print(f"姓名:{name},年龄:{age},成绩:{score}") check3("jack",10) check3("jack",10,67) check3(name="jack",age=10,score=67) check3("jack",age=10,score=67) check3("jack",10,score=67) print("*" * 30) # 4.不定长参数/可变参数:可以接受不定长的参数 # a.*xxx, # 注意1:*xxx,xxx被当成一个元组处理 def text1(*num): print(num) text1() text1(34) text1(34,56,67,68,7,8) text1(34,56,67,68,7,8,"abnfa",True) # 注意2:必需参数可以和不定长参数混合使用 def text2(num1,*num2): print(num1,num2) text2(10,45,56,67,6,8,7,8) # 注意3:如果不定长参数出现在形参列表的前面,则可以结合关键字参数完成传参 def text3(*num1,num2): print(num1,num2) # text3(10,45,56,67,6,8,7,8) # TypeError: text3() missing 1 required keyword-only argument: 'num2' text3(10,45,56,67,6,8,7,num2 = 8) # 注意4:*xxx在形参列表中只能被使用一次 # def text4(*num1,*num2): # print(num1,num2) # text4(45,57,6,77,8) print("*" * 30) # b.**xxx # 注意1:**xxx,xxx会被当做字典处理 def f1(**num): print(num) # 注意2:给**xxx的形参传参,则必须以key=value的方式传参 f1(x=10,y=20,z=30) # {'x': 10, 'y': 20, 'z': 30} # 注意3:**xxx在同一个函数的形参中只能出现一次 # def f2(**num1,**num2): # print(num1) # f2(x=10,y=20,z=30) # 注意4:*xxx和**xxx可以同时使用,但是,分别只能使用一次 def f3(*num1,**num2): print(num1,num2) f3(45,45,65,7,67) f3(45,45,65,7,67,a=4,b=467,fag="abc") f3(a=4,b=467,fag="abc") # 注意5:一般情况下,如果*xx和**xxx结合使用,命名为:*args,**kwargs
1.2参数传递
# 参数的传递:值传递和引用传递 """ 简述值传递和引用传递的区别 值传递:传参的时候,传递的是不可变的数据类型,如:int/float/str/tuple/bool,当形参发生修改,对实参没有影响 引用传递:传参的时候,传递的是可变的数据类型,如:list/dict/set等,当形参中的元素发生修改,则实参会随着修改 """ # 1.值传递 def func1(num): print(f"修改之前,num的地址:{id(num)}") num = 100 print(f"修改之后,num的地址:{id(num)}~~~~") temp = 45 func1(temp) print(f"temp的值:{temp}") print("*" * 50) # 2.引用传递 def func1(num): print(f"修改之前,num的地址:{id(num)}") num[1] = 100 print(f"修改之后,num的地址:{id(num)}~~~~") temp = [2,3,4] func1(temp) print(f"temp的值:{temp}")
2.返回值
# 1.return # 注意1:return是一个关键字,可以单独作为一条语句,只能使用在函数中,表示结束函数 # 注意2:同级的情况,在return的后面不添加任何语句,否则永远没有执行的机会 # a def show1(): print('1111') return print('over') show1() # b # 注意3:不同级的情况下,只要return有可能执行不到,return的后面是可以添加语句的 def show1(a): print('1111') if a > 10: return print('over') show1(20) # c.return和break """ return:使用在函数中,表示结束函数,不管return处于多少层循环中,只要执行到return,函数都会结束 break:使用在循环中,表示结束当前循环 """ def func1(): print('start') for i in range(3): for j in range(5): print(f"{i}={j}") if j == 2: break print("end") func1() print("*" * 50) def func2(): print('start') for i in range(3): for j in range(5): print(f"{i}={j}") if j == 2: return print("end") func2() print("*" * 50) # 2.return xxx:此处的return不但表示结束函数,还表示在函数调用的过程中将指定值返回 # 注意1:如果函数没有设置返回值,则函数调用完毕之后,默认返回None # 注意2:函数调用完毕之后,可以使用一个变量将返回值接出来 def show21(): print('222222') r1 = show21() # r1 = 返回值 print(r1) # 注意3:如果一个函数设置了返回值,则函数在哪里调用,返回值会返回值到哪里 def show22(): print('222~~~~~') return 66 r2 = show22() print(r2) print(show22()) # 如果一个函数的调用可以直接通过print打印,则说明该函数有返回值 def show23(): return 'abc',10,45 print(show23()) # ('abc', 10, 45) # 3.给函数设置返回值的意义 def add1(num1,num2): # 局部变量 total = num1 + num2 print(total) add1(23,10) # print(total) # NameError: name 'total' is not defined def add2(num1,num2): total = num1 + num2 return total r = add2(34,18) print(r) # list1 = [34,56,6] # list1.append(34) # print(list1)
3.函数的封装
""" def xxx(形参): 函数体【要实现的需求】 return 返回值 如果要封装一个函数,需要注意两个方面: 是否需要设置形参:如果需求中有未知项参与运算,则设置为形参 是否需要设置返回值:如果需求运算完是否有结果,如果有结果,则设置返回值 """ # 1.封装函数,比较两个数的大小,返回较大的值 def compare1(num1,num2): if num1 > num2: return num1 return num2 r = compare1(34,10) print(r) def compare2(num1,num2): if num1 > num2: return num1 elif num1 < num2: return num2 else: return "相等" r = compare2(10,10) print(r) # 2.封装函数,判断一个年份是否是闰年 def isleapyear(year): # if year % 4 == 0 and year % 100 != 0 or year % 400 == 0: # return True # return False return year % 4 == 0 and year % 100 != 0 or year % 400 == 0 r = isleapyear(2021) print(r) # 3.验证指定数是否是质数 def isprime(num): if num < 2: return False else: result = True for n in range(2, num): if num % n == 0: result = False break return result r = isprime(11) print(r)
4.匿名函数
概念:不再使用def这种标准形式定义函数,而是使用lambda表达式来创建函数,该函数没有函数名,被称为匿名函数,匿名函数也被称为lambda表达式
语法:lambda 形参列表:返回值
说明:
a.lambda只是一个表达式,用一行代码实现一个简单的逻辑,可以达到对函数的简化【优点】
b.lambda主体是一个表达式,而不是一个代码块,只能封装有限的逻辑【缺点】
c.lambda拥有自己的命名空间,不能访问自有列表之外或者全局命名空间里的参数
# 语法:lambda 形参列表: 返回值 # 1. # a.def标准函数 # 定义 def func1(): print('111') print(func1) # <function func1 at 0x106778f70> # 调用 r1 = func1() print(r1) # b.匿名函数 # 定义 # lambda :print('111!~~~~') f2 = lambda :print('111!~~~~') print(f2) # <function <lambda> at 0x106814790> # 调用 # 方式一:变量 = lambda xx:xxx,通过该变量就可以调用函数 r2 = f2() print(r2) # 方式二:不常用 # (lambda :print('111!~~~~'))() # 2. def add1(num1,num2): return num1 + num2 r1 = add1(34,5) print(r1) # 注意:匿名函数的返回值不需要return add2 = lambda num1,num2:num1 + num2 r2 = add2(23,9) print(r2) # 3. def even1(num): if num % 2 == 0: return True return False r1 = even1(10) print(r1) even2 = lambda num:True if num % 2 == 0 else False r2 = even2(35) print(r2)