一:函数入门
函数:就是可以重复使用的具有一定功能的代码。除了一些Python内置的函数以外,函数也可以自己定义
自定义函数:通过 def 定义的函数
自定义函数格式:
def 函数名(参数):
函数要去实现的功能代码
#调用函数
函数名(参数)
- 命名函数名和参数名时要符合变量命名规范
- 根据不同的需求,函数的参数可有可无,但函数名后面的括号和冒号一定要有
- 要注意功能代码处缩进
- 多个参数之间是通过英文逗号隔开的
- 注意函数定义之后是不会去执行的,要通过调用才会执行
#定义函数
def qiao():
print("函数,你好!")
#调用函数
qiao() #这里会自动执行其函数内部的功能代码
注意:
- 调用函数一定要在将这个函数定义完之后,先定义后使用
- 变量保存的是一段数据,而函数保存的则是一段代码
- 方法是用在类里面的,而函数则是用在程序里面的
1.函数参数的作用:
- 参数是函数中一个重要的组成部分,一个没有参数的函数会显得不是那么的灵活;相反,一个有参数的函数会更加的灵活,多变
- 参数分为形参和实参:
一:形参
参数名写在定义函数括号里面的叫做形参 -- 形式参数,它并不是真正的参数
def qiao(a,b): #此时a和b都是形参 -- 是未知值,需要我们去传入具体的数据 -- 实参
return a-b
(1)必备参数:
凡是写在定义定义函数括号里面的都是必备参数(除了*
)
def qiao(a,b): #此时a和b都是必备参数
return a-b
print(qiao(400,200)) #此时里面的数据就是实参
注意:
- 有多少个形式参数,就有多少个实际参数,多或者少都会报错
- 必备参数一定要写在所有类型参数的最前面,如果写在了后面,会报错
(2)默认参数:
有默认值,可以不用传入实参,使用默认的那个值;如果传了实参,则使用传入的那个实参的值
def qiao(a,b=200): #此时a是必备参数;b是默认参数
return a-b
print(qiao(600))
注意:
- 当形参有默认参数时,如果使用的是默认参数,则注意形参中的未知值决定是否需要实参
- 当与不定长参数一起使用时,要写在不定长参数的前面,不然,会报错
(3)不定长参数:
带有*
*args
**kwargs
,实参个数不固定,可有可无可多传也可不传
*
和**
表示不定长 默认args
和kwargs
表示不定长参数的参数名,也可以自定义名字*args
和**kwargs
会区分实参的形式,经过区分然后去接收*args
和**kwargs
两者的区别:
-
*args
会把接收到的位置参数存到元组,args
是元组类型 -
**kwargs
会把接收到的关键字参数存入字典,kwargs
是字典类型
#计算出给定数据的相加和
def qiao(*args): # *args会把接受到的数据参数存到元组,args是元组类型
s = 0
for i in args:
s += i
return s
print(qiao())
print(qiao(12,43,76,90)) #可以直接将函数打印输出
yue = qiao(12,42,78,0,64) #也可以将函数赋值给变量名在打印输出
print(yue)
#计算出给定数据的相加和
def qiao(a,*args): # a是必备参数,*args是不定长参数
s = 0
for i in args:
s += i
return s
print(qiao(12,43,76,90)) # 一个必备参数只会接收一个对应位置上的值;其余参数都被*args接收
#最后的运算结果会自动的把必备参数所对应的那个实参给排除掉,不参与相加
#剩下的由*args接收的参数自动相加
二:实参
写在调用函数括号里的,有具体的值,是真正的实际参数
(1)位置参数:
只要是单个的数据就都是位置参数,位置参数根据位置传参
def qiao(a,*args):
s = 0
for i in args:
s += i
return s
print(qiao(12,43,76,90)) #里面的参数都是位置参数
注意: 传入实参时注意位置参数一定要在关键字参数的前面
(2)关键字参数:
以变量赋值的形式的参数,关键字参数以参数名传参
def qiao(a,*args,**kwargs):
s = 0
for i in args:
s += i
return s
print(qiao(12,43,76,90,hjk="ertyui",yui=67,op=99)) #前四个参数是位置参数,后三个是关键字参数
注意:
- 当关键字参数中有与默认参数相同名字的变量名时那么变量名所赋的值会给到默认参数
- 当用关键字参数去传值时,要具体到参数的名字,此时是根据形参名去接收值,而不是位置
def qiao(a,b=10):
return a + b
print(qiao(a=46,b=90))
def qiao(a,b=20,*args,**kwargs):
print(a,b,args,kwargs)
print(qiao(12,43,76,90,hjk="ertyui",yui=67,op=99)) #此时默认参数b接收的值是43
2.函数返回值的作用:
在自定义调用函数运行完毕后,Python会默认返回一个None
,返回值也可以自己定义,返回值可以是任何类型,数据,甚至是表达式,返回值是根据自己的需求去定义的
自定义返回值格式:
def 函数名(参数):
函数要去实现的功能代码
return 返回值 #返回数据,结束自定义函数
#调用函数
函数名(参数)
注意:
return
属于结束语句,且return
在程序中只执行一次,写在return
后面的代码无意义,待return
执行完后,其后面的代码不会再去执行了,所以要把return
放到最后- 如果有返回值的话,要用
print()
函数将其打印在控制台上,不然控制台不会显示结果
def qiao():
name = "qiaoyue"
age = "未知"
return 10
print(qiao()) #控制台上显示10这个数字
3.函数嵌套:
在函数的里面定义另外的一个函数
def one():
print("这是外层函数")
def two():
print("这是内部函数")
one()
注意: 在此时不会执行内部函数,只会执行外层函数,因为内部函数two
是存储在one
函数里面的,属于局部函数,在one
函数外面是访问不到的,只能应用在one
函数的内部
def one():
print("这是外层函数")
def two():
print("这是内部函数")
two() #在函数内部被访问
注意: 在函数内部调用其它的函数不是函数的嵌套,在函数内部去定义子函数才是函数的嵌套
二:函数进阶
1.变量作用域:
(1)局部变量:只能在当前函数内部中使用,离开这个函数便访问不到了
def s():
a = 1 + 2 #这个a就是一个局部变量
print(a)
注意: 当离开这个函数再去访问局部变量时,会发生报错
(2)全局变量:可以在整个程序中使用,在这个程序中都可以被访问
b = 1+2 #这个b就是一个全局变量
def s():
c = 1 + b
print(b)
print(c)
print(s)
global
函数:提高局部变量的作用域,将其声明为全局变量,让其在函数外也可以被访问的到
global
函数的语法格式:global
局部变量名
#错误使用被声明的局部变量
def qiao():
name = "qiaoyue"
global name #将name声明为全局变量,提升其权限
age = "未知"
print(name)
注意: 在此时name
依旧无法被访问,因为name
在函数的内部,在没有调用这个函数前,是运行不到name
这个变量的,所以就算将其声明为全局变量也要受到函数的限制,注意在使用被声明过的局部变量时,要先调用这个局部变量所对应的函数
#假正确使用被声明的局部变量
def qiao():
name = "qiaoyue"
global name #将name声明为全局变量,提升其权限
age = "未知"
qiao()
print(name)
注意:
- 此时
name
依旧无法被访问,因为当执行完这个函数的时候,函数内部的数据就会被释放掉,在函数体里面的代码相当于是一段临时代码,用完就会在函数内部空间被释放。所以global
函数要写在被声明的局部变量之前,这样才会让其在函数内部和函数外部的空间中都有其存在 - 使用
global
函数:要先声明那个变量,在去定义那个函数里面的内容,这样才会有作用
#真正确使用被声明的局部变量
def qiao():
global name #将name声明为全局变量,提升其权限
name = "qiaoyue"
age = "未知"
qiao()
print(name)
2.高阶函数:
- 当一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归)二者满足其一则为高阶函数
- 当函数名作为参数进行传递的时候,返回的是这个传入的函数在内存中的地址
def one():
print("这是普通的函数")
def high(one): #此时并不完全算高阶函数,one只是一个可以任意命名的形参,当我们往这个形参里面传入的参数是一个函数名的时候才算是高阶函数
print("这是高阶函数")
high(40) #此时依旧是普通函数
high(one) #此时才是高阶函数,注意不要加上括号,加上后就不是传参了,而是对这个函数的调用
注意: 函数名加括号为调用,再去传给其它函数时会发生错误;不加为查看该函数在内存中的地址
使用高阶函数 -- 把函数当成当成另一个函数的参数进行传递:
def one():
print("这是普通的函数")
def high(canshu): #此时接收的是one函数的地址.2
print("这是高阶函数")
canshu() #此时是对one函数的调用.3
high(one) #此时传入的是one函数,准确的说应该是访问one函数的地址。1
注意:
- 内部函数代码是最后才去执行的,先执行创建函数并赋予这个函数在内存空间中的地址,再执行
high
函数的调用,然后去接收普通函数one
函数的地址,再执行one
函数的调用(在这个阶段one
函数会返回的就不在是它的函数地址了,而是one
函数内部运行的代码结果)最后再执行其内部代码 -- 内部代码先执行高阶函数,也就是外部函数;再执行普通函数,也就是内部函数。 - 重点是最后传进去的要是这个函数名,高阶函数的形参名并不重要,最后都会变成函数名。
使用高阶函数 -- 把函数当成另一个函数的返回值:
def one():
print("这是普通的函数")
def high(canshu):
print("这是高阶函数")
return canshu
print(high(one))
注意: 此时程序执行完成之后高阶函数high
返回的结果只是其本身的内部代码运行的结果和one
函数的地址。因为在high
函数中形参接收到one
函数的地址,后面的return
语句又把这个地址直接返回被print(high(one))
这条代码给接收到,所以one
函数内部代码并没有去运行
def one():
print("这是普通的函数")
def high(canshu):
print("这是高阶函数")
return canshu
print(high(one)())
注意: 此时程序执行完成之后高阶函数high返回的结果是其本身的内部代码运行的结果和one
函数内部代码运行的结果,和返回值None
。因为一个地址在给它加上一个括号的意思是调用,而在最外层还有一个print()
函数,意思是输出one
函数调用的一个结果,而在one
函数中并没有给它设置返回值,所以返回的是None
print(high(one)())
#这条语句等价于:
a = high(one) #这条语句的意思是:变量名(相当于函数的返回值 -- 地址) = 函数名(形参 -- 另一个函数名)
print(a()) #函数的返回值(地址)加上括号等同于函数名加上括号也就是回调
3.常用的内置高阶函数:
map()
函数:把序列中的每一个元素作用于函数上,最终返回
map()
函数的语法格式:map(函数,序列)
传入一个函数和一个序列,用来作映射
def c(x):
return x + 2
print(map(c,[23,46,89,66])) #最后输出的结果是一个map对象
注意: map()
函数的两个参数是必须要传的,并且map()
函数输出的是一个map
类型的对象和它在内存中的地址,我们是不能查看到内部的数据的,因为map()函数本身是一个迭代器,并不是一个容器,迭代器本身并不是存储数据的,只生成数据。但可以将其转换成其它的类型去查看生成的数据
def ccc(x):
return x + 2
print(list(map(ccc,[23,46,89,66]))) #将其转换成列表类型
filter()
函数:把序列中的每一个元素作用于函数上,如果函数返回的结果是True
,那么filter()
函数会过滤掉函数返回结果为False
的
filter()
函数的语法格式:filter()(函数,序列)
--传入一个函数和一个序列,用来作过滤
def aa():
if aa > 10:
return True
print(list(filter(aa,[45,2,7,19,88]))) #filter()也是一个迭代器
注意: filter(
)函数的两个参数是必须要传的
sorted()函数:排序,对任何单一的序列类型中的单一类型元素进行排序
- 当
sorted()
函数排序的是数字时:按照0~9的顺序排序- 当
sorted()
函数排序的是字母时:按照a~z的顺序排序- 当
sorted()
函数排序的是数字+字母的多种字符串元素时:看第一个字符,先排数字,在排字母- 当需要进行其它的排序时,按照需要填入函数名
sorted()
函数语法格式:sorted(序列,key=)
--key
接收的是一个函数名 -- 不带括号,指定排序方式的函数
a = "fghjcvbdfgh"
print(sorted(a))
b = ("aewfef","45","ijnhyu","90")
print(sorted(b))
注意: 当进行多种类型排序时,会发生报错,如:字符串+数值类型
b = ("aewfef","45","ijnhyu","90")
print(sorted(b,key=len)) #按照字符元素长短进行排序,短在前,长在后
print(sorted(b,key=len,reverse=True)) #长在前,短在后
#用列表中的sort()进行排序:
a = [
{
name="qi",age=12}
{
name="ao",age=16}
{
name="yue",age=18}
]
def ni(x):
return x["age"] #返回它对应的年龄,让其根据字典中的年龄大小进行排序
a.sort(key=ni) #因为列表中的是序列而不是单一的元素,且字典与字典之间无法进行比较,所以要用函数去指定排序的方式
print(a)
#用sorted()方法对字典进行排序:
print(sorted(a,key=a))
4.递归函数:
- 如果一个函数在其内部调用自身本身,那么这个函数就是递归函数
- 递归函数必须包含递归出口和递归体:
(1)递归出口:递归不可能一直进行下去,通常在问题的规模减小到一定程度后就需要结束递归。而这个终止条 件就是递归出口,递归出口必须保证在问题规模达到最小时结束递归,否则会导致无限递归,进 而使程序崩溃
(2)递归体:递归体是递归函数的主要部分,它描述了如何将一个规模最小的问题进一步分解,直到问题规模达 到递归出口所定义的大小,然后直接输出结果
#不完整递归,会报错,这里报错的原因是因为没有给递归出口,导致其一直运行下去
def a(x):
print(x)
return a(x-1)
print(a(5))
注意: 递归是有最大深度的,最大只能到1000,当递归次数太多时,会造成内存溢出
#完整递归
def a(x):
if x == 0: #递归出口
return x
print(x)
return a(x-1) #递归体(调用自身函数),使递归无限接近出口
print(a(5))
5.匿名函数:
匿名函数也是自定义函数,但是是没有名字的函数,匿名函数只能实现一些简单的功能
匿名函数的语法:用
lambda
去定义,使用时需要用到变量去接收
lambda 形参:表达式/函数的返回值
#计算两个数相加
#用函数实现
def a(x,y=100):
return x+y
print(a(2,6)) #计算2加6
#用匿名函数实现
a = lambda x,y=100:x+y
print(a(2,6))
#另一种语法格式
a = (lambda x:x)("Like You") #传入"Like You"并赋值给x最后在传给x
print(a)
注意: 在匿名函数中形参可以有很多个,但表达式/返回值只能有一个
#用不定长参数实现
a = lambda *args,**kwargs:sum(args) #可以接收任何参数,无论传什么传多少都可以接收
print(a(2,4,2,5,name="like"))
#在匿名函数中做判断
a = lambda x,y:y if y>x else x
print(a(56,78))