一、函数/方法
1.概述
在一个完整的项目中,某些功能可能会被反复使用,如果将反复出现的代码封装成函数,以后如果要继续使用该功能则直接使用函数即可,另外,如果要修改需求,只需要修改函数
本质:对某些特殊功能的封装
优点:
a.简化代码结构,提高应用的模块性
b.提高了代码的复用性
c.提高了代码维护性
# 需求:求圆的面积
# 1.
r1 = 45
area1 = 3.14 * r1 ** 2
print(area1)
r2 = 10
area2 = 3.14 * r2 ** 2
print(area2)
r3 = 5
area3 = 3.14 * r3 ** 2
print(area3)
# 2.优化
def area(r):
return 3.14 * r ** 2
print(area(45))
print(area(10))
print(area(5))
2.定义
语法:
def 函数名(变量1,变量2....):
函数体
return 返回值
说明:
a.def是一个关键字,是definition的缩写,专门定义函数
b.函数名:遵循合法标识符的规则和规范即可,尽量做到见名知意
c.(变量1,变量2....):被称为形式参数,是一个参数列表,都只是没有赋值的变量
d.函数体:封装某些特殊的功能
e.return是一个关键字,表示返回,只能用在函数中,表示结束函数,可以单独使用,也可以携带数据,当携带数据,则表示该函数的返回值
f.返回值:常量,变量,表达式
g.函数的定义分为两部分:函数的声明和函数的实现
h.变量1,变量2.... 和 return 返回值 可以根据具体的需求选择性的省略
"""
def 函数名(参数):
函数体
return 返回值
"""
"""
注意:
a.在实际项目开发中,一般情况下将不同的功能封装成不同的函数
b.函数定义的过程,相当于将函数加载到内存中的过程,定义函数相当于定义变量,函数名相当于是一个变量名
c.函数被定义之后,如果不使用【调用】,则不会执行其中的代码
"""
# print('start')
# 1.无参无返回值
def func1():
print("11111")
# print('end')
# 2.有参无返回值
def func2(a):
print("22222")
# 3.无参有返回值
def func3():
print("33333")
return 10
# 4.有参有返回值
def func4(a):
print("444444")
return 10
# 扩展
num = 10
print(type(num)) # <class 'int'>
print(type(func4)) # <class 'function'>
3.调用
def 函数名(形式参数):
函数体
调用函数的语法:函数名(实际参数)
形式参数:出现在函数的声明部分,简称形参,可以理解为是一个等待赋值的变量
实际参数:出现在函数的调用部分,简称实参,实参就是给形参赋值的数据
调用函数的过程实际上就是传参的过程
传参的过程:实参给形参赋值的过程,如果没有形参,则也没有实参
print('start')
# 1.直接调用
def func1():
print("11111")
func1()
print('end')
def func2(a):
print("22222",a)
func2(34)
def func3():
print("33333")
return 10
func3()
def func4(a):
print("444444",a)
return 10
func4('abc')
print("*" * 50)
# 2.相互调用
def show1():
print("show~~~11111")
show3()
def show2():
print("show~~~22222")
def show3():
show2()
print("show~~~33333")
show1()
# 3.恶意调用,注意:避免出现下面函数调用的写法
# a
# def f1():
# print("hello")
# f1()
# f1()
# b
# def f1():
# print("hello~~~~1111")
# f2()
# def f2():
# print("hello~~~2222")
# f1()
# f1()
"""
注意:
a.函数一旦被定义之后,需要手动调用,否则无法执行函数体
b.在代码执行的过程中,一旦遇到函数的调用,则优先执行对应的函数体,当函数执行完毕,
回到函数调用的位置,继续执行后面的代码
c.函数可以被直接调用,也可以函数之间相互调用,也可以将函数的调用应用在if语句或者运算表达式中
"""
4.参数
4.1基本使用
# 1.当封装一个函数的时候,是否需要设置参数
# 判断依据:查看需求中是否有未知项参与运算
# a.封装一个函数,求两个数的和
def add(num1,num2):
total = num1 + num2
print(total)
# b.封装一个函数,实现对数字列表的升序排序
def mysort(numlist):
numlist.sort()
print(numlist)
# 2.当调用函数的时候,实参给形参赋值需要注意的事项
add(34,67)
mysort([345,17,10])
# 3.
# a.必需参数
def func1(num1,num2):
t = num1 + num2
print(t)
func1(29,10)
# b.默认参数
def func2(num1,num2=0):
t = num1 + num2
print(t)
func2(29)
func2(29,10)
# c.关键字参数
def func3(num1,num2=0):
print(num1,num2)
t = num1 + num2
print(t)
func3(num2=5,num1=76)
# d.不定长参数
# *x:x当成元组处理
def func41(*num): # 打包
print(num) # 元组
print(*num) # 拆包
func41()
func41(34,56)
func41(23,5,7,8,9)
# **x:x当成字典处理
def func42(**num): # 打包
print(num)
func42()
func42(x=10,y=20)
"""
总结:
a.实参和形参的数量需要匹配
b.根据函数体的实现,实现和需求中使用的类型需要匹配
"""
4.2参数分类
参数分类:
- 必需参数:常用
- 默认参数
- 关键字参数
- 不定长参数【可变参数】
-
# 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
4.3参数传递
"""
【面试题】值传递和引用传递的区别
值传递:传参的时候,传递的是不可变的数据类型,如:int float bool str tuple,当形参发生改变,对实参没有影响
引用传递:传参的时候,传递的是可变的数据类型,如:list dict set,当形参中的元素发生改变,实参会随着修改
"""
# 1.值传递
def func1(num):
num = 100
print(f"num={num}")
n = 66
func1(n)
print(f"n={n}") # 66
"""
num=100
n=66
"""
# 2.引用传递
def func1(num):
num[1] = 100 # 实参会随着修改
# num = 100 # 实参不会随着修改
print(f"num={num}")
n = [2,3,4]
func1(n)
print(f"n={n}")
"""
num=[2, 100, 4]
n=[2, 100, 4]
"""
二、函数基础【重点掌握】
1.返回值
return关键字的使用,注意:return只能使用在函数中
# 函数的返回值:函数执行完的结果,在哪里调用函数,就可以在哪里将返回值接出来
# 1.注意1:如果给函数未设置返回值,默认返回None
def func1():
print('1111')
r1 = func1() # 解释:r1 = func1函数的返回值
print(r1) # None
# 2.注意2:return是一个关键字,可以单独使用,表示结束函数,
# 所以return后面的,和return平级的代码没有执行的机会,在和return平级的后面一般不书写代码
# a.
def func21(a,b):
print('22222~~~1111')
return # return肯定会执行
# print("over") # 肯定不会执行,永远没有执行的机会
func21(4,2)
print('*' * 30)
# b
# 注意3:和return不平级的情况下,return后面的代码可能有执行的机会
def func22(a,b):
print('22222~~~~2222')
if a + b > 5:
return # return可能执行
print("over") # 有执行的机会
func22(4,2)
# c.
def func31():
for i in range(3): # 0 1 2
for j in range(5): # 0 1 2 3 4
print(f"{i}={j}")
if j == 2:
break # break结束当前循环
print('over~~31')
func31()
"""
0=0
0=1
0=2
1=0
1=1
1=2
2=0
2=1
2=2
over~~31
"""
# 注意4:不管return书写在多少层嵌套循环中,只要执行到return,函数立马结束
def func32():
for i in range(3):
for j in range(5):
print(f"{i}={j}")
if j == 2:
return
print('over~~32')
func32()
"""
0=0
0=1
0=2
"""
# 3.return xxx
# 注意5:return xxx表示将指定的数据在函数执行完毕之后返回
# 返回值可以是常用,变量,表达式
# a
def func41():
return "abc"
r41 = func41()
print(r41)
# b.
def func42(a):
return a + 5
r42 = func42(34)
print(r42)
# c.
def func43(a,b):
return a > b
r43 = func43(3,89)
print(r43)
# d.
def func44(a,b):
return a,b # 打包
r44 = func44(23,78)
print(r44) # (23, 78)
# e.
def func45(a,b):
if a > b:
return a
elif a < b:
return b
else:
return "相等"
r45 = func45(56,56)
print(r45)
print("*" * 50)
# 4.return的意义
def func51():
num1 = 66 # num1只能在函数内部使用
print(num1)
func51()
# print(num1 + 5) # NameError: name 'num1' is not defined
def func51():
num1 = 66
return num1
r5 = func51()
print(r5 + 5)
# 举例
list1 = [34,65]
list1.append(10)
print(list1)
r = list1.pop()
print(r)
2.函数练习
如何封装函数:
a.是否需要设置参数:需求中是否有未知项参与运算,有几个未知项参与运算
b.是否需要设置返回值:函数体执行完毕之后是否有结果 或者 结果是否需要在函数的外面使用
# 1.封装一个函数,验证一个年是否是闰年
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) # isdigit()
print(r)
# 2.封装一个函数 获取指定月的天数
def get_days(year,month):
if month in [4,6,9,11]:
return 30
elif month in [1,3,5,7,8,10,12]:
return 31
else:
if isleapyear(year):
return 29
return 28
r2 = get_days(2020,2)
print(r2)
# 9.模拟列表中sort的使用,对列表进行排序,默认升序,也可以降序
def mysort(numlist,reverse=False):
if reverse:
# 降序
for i in range(len(numlist) - 1):
for j in range(len(numlist) - 1 - i):
if numlist[j] < numlist[j + 1]:
numlist[j],numlist[j + 1] = numlist[j + 1],numlist[j]
else:
# 升序
for i in range(len(numlist) - 1):
for j in range(len(numlist) - 1 - i):
if numlist[j] > numlist[j + 1]:
numlist[j],numlist[j + 1] = numlist[j + 1],numlist[j]
list1 = [34,56,6,2,34,6]
mysort(list1) # 升序
print(list1)
ist1 = [34,56,6,2,34,6]
mysort(list1,reverse=True) # 降序
print(list1)
三、匿名函数【重点掌握】
概念:不再使用def这种标准形式定义函数,而是使用lambda表达式来创建函数,该函数没有函数名,被称为匿名函数
语法:lambda 形参列表:函数体
说明:
a.lambda只是一个表达式,用一行代码实现一个简单的逻辑,可以达到对函数的简化【优点】
b.lambda主体是一个表达式,而不是一个代码块,只能封装有限的逻辑【缺点】
c.lambda拥有自己的命名空间,不能访问自有列表之外或者全局命名空间里的参数
# 1.基本使用
# a.
def func1():
print('11111')
func1()
print(func1) # <function func1 at 0x103c9c1e0>
print(type(func1)) # <class 'function'>
# b.
# 语法:lambda 形参列表:函数体
# 方式一
func2 = lambda : print('2222')
print(func2) # <function <lambda> at 0x1049916a8>
print(type(func2)) # <class 'function'>
# 调用匿名函数
func2()
# 方式二
(lambda : print('2222~~~~~'))()
"""
匿名函数的定义及调用
方式一:
func2 = lambda : print('2222')
func2()
方式二:
(lambda : print('2222~~~~~'))()
"""
# 注意:不管是def定义的函数,还是lambda定义的匿名函数,函数定义完成之后,都需要手动调用
# 2.应用
# a.
def add1(num1,num2):
return num1 + num2
r1 = add1(3,6)
print(r1)
# 注意:匿名函数中的返回值可以直接书写,不需要借助于return
add2 = lambda num1,num2: num1 + num2
r2 = add2(2,5)
print(r2)
# b.
def isleapyear1(year):
if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
return '闰年'
return '平年'
r1 = isleapyear1(2021)
print(r1)
isleapyear2 = lambda year: '闰年' if year % 4 == 0 and year % 100 != 0 or year % 400 == 0 else '平年'
r2 = isleapyear2(2020)
print(r2)
# c
iseven = lambda num:True if num % 2 == 0 else False
r = iseven(34)
print(r)
# 3.注意事项
# 注意:匿名函数本质上仍然是一个函数,所以默认参数,关键字参数,不定长参数都可以使用
# a
f1 = lambda a,b = 0:a + b
print(f1(4))
print(f1(4,2))
# b.
print(f1(a = 5))
print(f1(a = 5,b = 9))
print(f1(b = 6,a = 5))
# c
f1 = lambda *num:sum(num)
print(f1(34,56,6,7,8))
# 4.使用场景
# 常用于其他函数的参数使用,如:sort(),常用高阶函数:sorted,map等
# 需求:列表按学生成绩从大到小排序
students = [
{'name': '小花', 'age': 19, 'score': 90, 'gender': '女', 'tel':
'15300022839'},
{'name': '明明', 'age': 20, 'score': 40, 'gender': '男', 'tel':
'15300022838'},
{'name': '华仔', 'age': 18, 'score': 90, 'gender': '女', 'tel':
'15300022839'},
{'name': '静静', 'age': 16, 'score': 90, 'gender': '不明', 'tel':
'15300022428'},
{'name': 'Tom', 'age': 17, 'score': 59, 'gender': '不明', 'tel':
'15300022839'},
{'name': 'Bob', 'age': 18, 'score': 90, 'gender': '男', 'tel':
'15300022839'}
]
"""
列表.sort()的工作原理
a.如果列表元素是数字,底层是通过>或<进行数字比较的
b.如果列表元素是字符串,底层是通过>或<进行ASCII码比较的
c.但是,如果列表中的元素是字典等不支持>或<的数据,则需要自定义排序规则,格式:sort(key=排序函数)
d.如果自定义排序规则,列表.sort(key=func)的工作原理:将列表中的元素依次传递给func的参数
func的返回值将作为排序的依据【func的返回值必须要支持>或<的比较】
"""
# a.
# def func(subdict):
# return subdict['score']
# students.sort(reverse=True,key=func)
# print(students)
# b.
students.sort(reverse=True,key=lambda subdict:subdict['score'])
print(students)
# 【思考题】/【面试题】
def func():
l = []
for i in range(5):
l.append(lambda x:i * x)
return l
r = func()
print(r[0](2))
print(r[1](2))
print(r[2](2))
print(r[3](2))
print(r[4](2))