python3 函数
一.函数
1.函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
2.函数能提高应用的模块性,和代码的重复利用率
3.函数文档字符串用三引号引起,python使用它们来生成有关程序中函数的文档,用来说明函数
4.函数可分为:内置函数BIF,自定义函数,第三方函数
二.定义和调用
1.定义:以 def 关键词开头,后接函数标识符名称和圆括号 ( )
def 函数名(形参):
函数体
2.调用:(1)直接调用:函数名(实参),(2)变量名=函数名(实参)来把函数返回值赋值给变量
3.函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”
4.函数必须先定义才能调用
5.函数定义若重名,则忽略最旧的,只调用最新的函数,以新覆盖旧
三.参数
1.形参和实参
(1)形参:函数定义时,函数完成其工作所需的一项信息
(2)实参:函数调用时,传递给函数的信息
2.函数的形参类型按顺序:必选参数、默认值参数、可变参数、命名关键字参数和关键字参
3.必选参数:一个实参关联一个形参(一个值关联一个变量)
(1)形参:变量名。不能试图用‘元组’等的形式
(2)实参:1.位置实参:值,实参的顺序要与形参的顺序相同;2.关键字实参:每个实参由变量名和值组成
4.默认值参数:默认值参数必须指向不变对象,给形参添加一个默认值
(1)形参:变量名=默认值。使用时,必须列出没有默认值的形参,再列出有默认值的形参,使python能正确地解读位置实参
(2)实参:如果传入参数值,则使用参数值,如果没有传递参数值,则会使用默认值
5.可变参数:可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个;能处理比当初声明时更多的参数,
(1)形参:*变量名。一般使用:*args。表示:python创建一个名为args的空元组,并将收到的所有值都封装到这个元组中
(2)实参:0个或多个值,放在位置实参和关键字实参后面,只能通过位置传值,python自动匹配
6.关键字参数:需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息
(1)形参:**变量名。一般使用:**kwargs。表示:python创建一个名为kwargs的空字典,并将收到的所有值都封装到这个字典中
(2)实参:0个或多个关键字实参(变量名-值),放在最后
7.命令关键字参数:限制关键字参数的名字。命名关键字参数需要一个特殊分隔符*
,*
后面的参数被视为命名关键字参数
(1)定义时,如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*
(2)调用时,命名关键字参数必须传入参数名
1 #参数
2 def printinfo(a, b,*args,c=4,**kwargs):
3 print('必选参数',a,b)
4 print('默认参数',c)
5 print('可变参数1',args)
6 print('可变参数2',*args)
7 print('关键字参数1',kwargs)
8 print('关键字参数2',*kwargs)
9
10 printinfo(3,4,5,(42,35),name='a',c=1,age=16,)
11 #按位置传入参数
12 #3传入a,4传入b
13 #4后面的被认为*args,被判定为一个元组
14 #如果碰到关键字传参,先判定是否是默认参数传参,如果不是,则判定为关键字传参
15 -------------------------------------------------------------------------
16 必选参数 3 4
17 默认参数 1
18 可变参数1 (5, (42, 35))
19 可变参数2 5 (42, 35)
20 关键字参数1 {'name': 'a', 'age': 16}
21 关键字参数2 name age
8.总结:
(1)定义函数时,先设置必选参数(变量名),接着默认值函数(变量名+值),再者可变参数(*变量名),最后关键字参数(**变量名)
(2)调用函数时,依次传递参数,对于必选参数,直接传递参数(值)或根据关键字传参(变量名+值);对于默认值参数,可以不传参或直接传参(值)或根据关键字修改默认值(变量名+值);
对于可变参数,传入0个或多个值(变量名),对于关键字参数,传入传入0个或多个参数(变量名+值)
四.函数的拆包和偏函数
1.函数参数的拆包(解包)
装包:把传递的参数,包装成一个集合;拆包:把集合参数再次分解为单独的个体
1 def my_sum(a,b,c,d):
2 print(a+b+c+d)
3
4 def test(*args):
5 '''*args:可变参数,接收0个或多个参数封装成元组'''
6 print('未拆包表示:',args)#多个参数封装的元组,(1,2,3)一个元素
7 print('拆包表示:',*args)#把元组拆分成单个元素的形式,1,2,3多个元素
8 my_sum(args[0],args[1],args[2],args[3])
9 my_sum(*args)
10
11 test(1,2,3,4)
12 ---------------------------------------------
13 未拆包表示: (1, 2, 3, 4)
14 拆包表示: 1 2 3 4
15 10
16 10
1 def mysum(e,f):
2 print(e)
3 print(f)
4
5 def test2(**kwargs):
6 '''**kwargs:关键字参数,接收0个或多个关键字参数封装成字典'''
7 print('未拆包表示:',kwargs)#字典, {'e': 1, 'f': 2}一个元素
8 print('拆包表示:',*kwargs)#*拆解出key,e f多个元素
9 # print(**kwargs)#相当于*(*kwargs)拆包多个元素,所以会报错
10 mysum(**kwargs) #把整个字典作为参数传递给函数,相当mysum(e=1,f=2)
11 test2(e=1,f=2)
12 --------------------------------------------
13 未拆包表示: {'e': 1, 'f': 2}
14 拆包表示: e f
15 1
16 2
17
2..偏函数:指定函数的参数为某个固定值。当函数的参数个数太多,需要简化时,functools.partial创建一个偏函数,可以接收函数对象、*args
和**kw
这3个参数
偏函数把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
1 def test(a,b,c,d):
2 print(a+b+c+d)
3
4 def test2(a,b,c,d=2):
5 test(a,b,c,d)
6
7 test2(1,2,3)
8
9 import functools
10 newfunction=functools.partial(test,d=3)
11 print(newfunction,type(newfunction))
12 newfunction(1,2,3)
13 ---------------------------------------------------------------------------
14
15 8
16 functools.partial(<function test at 0x056BDFA8>, d=3) <class 'functools.partial'>
17 9
五.return语句
1.如果没有使用return语句指定返回值,python也不是什么都不返回,它会返回一个None对象,所以说python所有函数都有返回值
2.函数调用时return返回一个表达式,有返回值的函数可以对改值进行保存赋值等操作
3.return可以返回多个值并调用,可以以列表,元组,字典的形式以一个整体返回,默认以元组形式
4.return还有一个功能:结束函数(相当于函数中break功能),下面的不执行
5.返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量
6.函数中return和print的区别
(1)print是函数调用直接打印出来,输出数据到控制端
(2)return是这个函数调用返回一个值,如果一个函数没有返回值,那么这个函数的计算结果无法在其他地方使用
1 def test():
2 i=7
3 return i#返回计算的值
4
5 print('1:',' ');test()#调用test函数,控制台没有输出
6 print('2:',test())#调用并操作(打印)test()函数。test函数中没有输出,test函数的返回值为7
7 print('3:',test()==7) #调用并操作(打印)test()函数,调用时没有打印的操作,test函数的值为7,输出比较的值True
8
9
10 def test2():
11 i=7
12 print(i)#输出数据到控制端
13 print('4:',end=' ');test2()#调用test2函数,(主要看里面有什么操作),函数中有print输出7
14 print('5:',test2())#调用并操作(打印)test2()函数。test函数中打印7,test函数中没有返回值(None)
15 print('6:',test2()==7)#调用并操作(打印)test2()函数,调用时打印7,test函数的值为None,输出比较的值False
16 -------------------------------------------------------------------------------
17 1:
18 2: 7
19 3: True
20 4: 7
21 7
22 5: None
23 7
24 6: False
六.匿名函数lambda 函数
1.lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去,lambda函数只能写一个表达式,表达式的结果就是返回值
2.lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
3.lambda [arg1 [,arg2,.....argn]]:expression
1 q=lambda x:x*x+1#定义一个函数q,参数x满足x*x+1
2 print(type(q))
3 print(q(2))
4 -----------------------------------------------------------------
5 <class 'function'>
6 5
七.变量作用域
1.程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的
2.变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称
3.作用域一共有4种:L (Local) 局部作用域,E (Enclosing) 闭包函数外的函数中(比如闭包),G (Global) 全局作用域,B (Built-in) 内建作用域;以 L –> E –> G –>B 的规则查找
4.Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域
5.其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
1 x = int(2.9) # 内建作用域
2 g_count = 0 # 全局作用域
3 def outer():
4 o_count = 1 # 闭包函数外的函数中
5 def inner():
6 i_count = 2 # 局部作用域
6.闭包:在函数嵌套的前提下,内层函数引用外层函数的变量(包括参数),外层函数又把内层函数当做返回值进行返回
闭包中,如果要修改引用的外层变量需要使用nonlocal,否则当做是闭包内新定义的变量
1 #闭包 有函数动态生成的函数
2 def mi_num(x):
3 def mi(y):
4 y=y**x
5 return y
6 return mi#函数以参数的形式返回
7 a=mi_num(4)#4次方,a是一个函数
8 print(a(2))#输出2的4次方
9 -------------------------------------------------------------------
10 16
7.定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域
8.全局变量和局部变量
(1)局部变量是在一个函数内部定义的变量;作用域为函数内部;可以用locals()函数查看局部变量
(2)全局变量是在函数外部,文件最外层定义的变量;作用域为整个文件内部;可以利用golbals()函数查看全局变量
(3)局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问
(4)当内部作用域想修改外部作用域的变量时(比如函数中修改全局变量的值),就要用到global关键字,里面用外面的变量;函数内部可以更新外部的变量
(5)修改嵌套作用域中的变量(比如在嵌套函数中,希望在内部函数修改外部函数的局部变量)则需要 nonlocal 关键字,函数中对于不可变数据类型作为全局变量时,一定加global,对于操作可变数据类型全局变量时,可不加global
1 num = 1
2 def fun1():
3 global num # 需要使用 global 关键字声明
4 print(num)
5 num = 123
6 print(num)
7 fun1()
8
9 def outer():
10 num = 10
11 def inner():
12 nonlocal num # nonlocal关键字声明
13 num = 100
14 print(num)
15 inner()
16 print(num)
17 outer()
18 -------------------------------------------------------------
19 1
20 123
21 100
22 100
八.函数装饰器
1.在函数名以及函数体不改变的前提下,给一个函数附加一些额外代码,扩展函数功能
2.装饰器的执行时间是立即执行
3.本身是一个函数,以函数作为一个输入,返回另一个函数
4.对有返回值的函数进行修饰,无论什么场景,保证函数返回值一致
1 def zhanshi():
2 print('ok')
3
4 def jiaprint(func): #func以函数为参数的装饰器函数
5 def wrapper():
6 print('运行的函数名',func.__name__)#输出函数的名称
7 func() #执行参数函数的功能
8 print('over')
9 return wrapper
10 zhanshi = jiaprint(zhanshi) #调用函数装饰器
11 zhanshi()
12
13
14 #等价于:
15 #def zhanshi():
16 # print('ok')
17 # def jiaprint(func):
18 # print('运行的函数名',func.__name__)
19 # func()
20 # print('over')
21 # jiaprint(zhanshi)
22 ----------------------------------------------------------------------
23 运行的函数名 zhanshi
24 ok
25 over
1 def jiaprint(func): #func以函数为参数的装饰器函数
2 def wrapper():
3 print('运行的函数名',func.__name__)#输出函数的名称
4 func() #执行参数函数的功能
5 print('over')
6 return wrapper
7
8 @jiaprint#等价于zhanshi = jiaprint(zhanshi)用函数装饰器
9 def zhanshi2():
10 print('nono')
11 zhanshi2()#zhanshi2已经用了装饰器
12 --------------------------------------------------------------------
13 运行的函数名 zhanshi2
14 nono
15 over
1 def checklogin(func):#利用checklogin函数对某一函数进行操作
2 def inner():#定义一个新的函数进行返回
3 print('登录验证...')#增加的功能
4 func()#保持原有函数的功能
5 return inner#返回值是一个新的函数
6
7
8 #语法糖 写法
9 @checklogin#利用checklogin函数对下面的函数进行增加功能的操作
10 def fss():
11 print('发说说')
12 # fss=checklogin(fss)相当于@checklogin
13
14 @checklogin#利用checklogin函数对下面的函数进行增加功能的操作
15 def ftp():
16 print('发图片')
17 # ftp=checklogin(ftp)相当于@checklogin
18
19 a=1
20 if a==1:
21 fss()
22 else:
23 ftp()
24 ---------------------------------------------------------------------------
25 登录验证...
26 发说说
1 def line(func):
2 def inner():
3 print('-'*30)
4 func()
5 return inner
6
7 def star(func):
8 def inner():
9 print('*'*30)
10 func()
11 return inner
12
13
14 #从上到下装饰,从下到上执行
15 @line#print_=line(print_)先装饰
16 @star#print_=star(print_)先执行
17 def print_():
18 print('打印')
19
20 print_()
21 ------------------------------------------
22 ------------------------------
23 ******************************
24 打印
1 def zsq(func):
2 def inner(*args,**kwargs):
3 print('*'*30)
4 print(args,kwargs)
5 func(*args,**kwargs)
6 return inner
7 #对有参函数进行装饰,利用不定长参数
8 @zsq
9 def pnum(num,num2):
10 print(num,num2)
11 @zsq
12 def pnum2(num):
13 print(num)
14
15 pnum(123,234)
16 pnum2(26)
17 ---------------------------------------------------
18 ******************************
19 (123, 234) {}
20 123 234
21 ******************************
22 (26,) {}
23 26
1 #带有参数的装饰器
2 #通过@装饰器(参数)的方式,调用这个函数,并传递参数,并把返回值再次当做装饰器进行使用
3 #先计算@后面的内容,把这个内容当做是装饰器
4 def getzsq(char):
5 def zsq(func):
6 def inner():
7 print(char*30)
8 func()
9 return inner
10 return zsq
11 @getzsq('*')
12 def f1():
13 print('66')
14
15 f1()
16 ------------------------------------------------------
17 ******************************
18 66
九.递归函数
1.在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数
2.递归:(1)函数调用自身;(2)设置正确的返回条件