Python基础知识-09-函数
Posted 魔降风云变
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python基础知识-09-函数相关的知识,希望对你有一定的参考价值。
1、函数介绍
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()
。但你也可以自己创建函数,这被叫做用户自定义函数。
def 函数名(参数列表):
函数体d
函数名(参数)
函数名(参数)
2、函数使用优缺点:
公司随随便便几百上千行。可读性,重用性,函数,面向过程编程
优点:
缺点:
面向过程,可以将可重复性的代码做成一个函数,用参数代替变化的量,实现具有重复性操作的功能。
当事物需要做这个操作的时候,调用函数即可实现功能。#自己理解
#发邮件:设置里面开启pop3,smtp服务器 ,往smtp服务器发邮件
比如发邮件,很多对象都使用的一个动作,写成函数,调用函数。避免代码冗余。
什么情况写函数,就是为了能重复使用某个功能,就写成函数,一个功能一个函数。或者是为了方便阅读,增加代码可读性
函数式编程是做什么的?避免重复性代码。代码拆分,增强可移植性,可读性
本质:将N行代码拿到别处并给他起个名字,以后通过名字就可以找到这段代码并执行。
场景:代码重复执行。
代码量特别多超过一屏,可以选择通过函数进行代码的分割。
3、函数定义:
你可以定义一个由自己想要功能的函数,以下是简单的规则:
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None
。
语法:
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
函数执行: def xiaoma(): print("魔降风云变") xiaoma() ---------结果: 魔降风云变
4、函数调用
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执
行。
函数不调用,内部代码不执行。调用后用不用变量接收返回值,函数都会执行。
def xiaoma(): print("魔降风云变") xiaoma() ---------结果: 魔降风云变 def xiaoma(): print("魔降风云变") a=xiaoma() ----------结果: 魔降风云变
def xiaoma():
print("魔降风云变")
def mcw(): #函数调用函数
print("我是:")
xiaoma()
mcw()
--------------结果:
我是:
魔降风云变
5、函数传参
5.1、函数传参简介
不同的对象做相同的操作,可以定义函数。如果每个对象还有些区别,那么有区别的地方使用函数传参
。
定义带参数的函数的时候
函数式编程。通过传参,返回不同的值,返回不同的参数。同一个功能不同的地方就使用传参
形式参数(形参):形参就是形式上的参数,可以理解为数学的X,没有实际的值,通过别人赋值后才有
意义。相当于变量。
实际参数(实参):实参就是实际意义上的参数,是一个实际存在的参数,可以是字符串或是数字等
函数里面使用字符串格式化
函数可以定死了,也可以传递变量。写函数不一定需要参数。如果有变的,使用参数,没有变的就定死
了就可以,看实际情况了。
def eat(arg1,arg2):
print("%s喜欢吃%s"%(arg1,arg2))
eat("小马过河","米饭")
eat("小明","面条")
-----------结果:
小马过河喜欢吃米饭
小明喜欢吃面条
5.1没有函数传参 案例1: 使用函数只计算某一个列表内元素的和: def list_sum(): li = [1, 2, 3] sum=0 for i in li: sum+=i print(sum) list_sum() -----------结果 6 5.2一个函数传参: 案例2: 使用函数计算指定列表内元素的和: def list_sum(li): sum=0 for i in li: sum+=i print(sum) info=[1,2,3] list_sum(info) -------------结果: 6 报错问题1: 报错:函数没有形参,调用函数时带着参数的报错: def list_sum(): sum=0 for i in li: sum+=i print(sum) info=[1,2,3] list_sum(info) #调用时,可以直接做参数,也可以用变量做实参 -------------------结果: list_sum(info) TypeError: list_sum() takes 0 positional arguments but 1 was given 5.3多个函数传参: def xiaoma(arg1,arg2): print(arg1+arg2) xiaoma(2,3) -----------结果: 5 报错问题2:传参传少了 def xiaoma(arg1,arg2): print(arg1+arg2) xiaoma(2) -----------结果: xiaoma(2) TypeError: xiaoma() missing 1 required positional argument: \'arg2\' 报错问题3:传参传多了 def xiaoma(arg1,arg2): print(arg1+arg2) xiaoma(2,3,4) ------------结果: xiaoma(2,3,4) TypeError: xiaoma() takes 2 positional arguments but 3 were given
严格按照顺序来传参数,按位置一一对应。
5.2基本参数知识
- 任意个数
- 任意类型
def func(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8): print(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) func(1,False,None,"mcw",["xiaoma","1"],(1,2),{"name":"xiaoma"},{3,4}) ------结果: 1 False None mcw [\'xiaoma\', \'1\'] (1, 2) {\'name\': \'xiaoma\'} {3, 4}
5.3、位置传参(调用函数并传入参数)【执行】
位置传参:根据位置意义对应传递参数
def func(a1, a2): print(a1, a2) func(1, 3) ------------结果: 1 3
5.4关键字传参【执行】
关键字传参:指定形参接收实参
def func(a1, a2, a3): print(a1, a2, a3) func(1,2,a3=9) func(1,a2=2,a3=9) func(a1=1,a2=2,a3=9) ------------------结果: 1 2 9 1 2 9 1 2 9 def func(a1, a2, a3): print(a1, a2, a3) func(a1=1,2,3) # 错误 -------------结果: SyntaxError: positional argument follows keyword argument follows关键字定位论点论据
5.5默认参数【定义】
使用场景:定义函数默认参数,方便
指定形参等于什么参数,如果没有接收到实参,那么函数就使用默认参数
def func(a1,a2,a3=9,a4=10): #a3默认9,a4默认10,调用时可以传可以不传。;给默认传参传了参数就用传进函数的参数,否则用的默认参数。比如open函数有默认的参数。
print(a1,a2,a3,a4)
func(11,22) func(11,22,10) func(11,22,10,100) func(11,22,10,a4=100) func(11,22,a3=10,a4=100) func(11,a2=22,a3=10,a4=100) func(a1=11,a2=22,a3=10,a4=100) -------------------结果: 11 22 9 10 11 22 10 10 11 22 10 100 11 22 10 100 11 22 10 100 11 22 10 100 11 22 10 100
5.6万能参数(打散)
*args:传递多个实参给形参*args,并让函数以元组的形式来接收外部传参
- 实参前面加*号,将实参内的每个元素传到*args元组中,而非实参本身。
*kwargs:传递多个键值对或字典给*kwargs,并且在函数内以字典的形式存在
- 实参字典前面加**给*kwargs,会将实参内每个键值对添加到*kwargs字典中,而非实参字典本身
-
*args
-
可以接受任意个数的位置参数,并将参数转换成元组。
-
*args只能接收n个参数。传入多个实参时,都放到args这个元组里面。如果传入元组参数,那么元组作为args的单个元素。如果*(),实参元组前面有*,那么实参元组内的每个元素都放到形参构成的元组内,即形参
-
构成的元组内是实参内的各个元素。只能位置传参,不能关键字传参#假设可以关键字传参,那么设定之后,它后面就接收不了参数
-
了,所以不可以做关键字传参
-
使用场景:不确定需要传参个数的时候使用万能参数。
-
调用函数无 *
def func(*args): print(args) #*args只能接收n个参数。传入多个实参时,都放到args这个元组里面。 func(1,2,3,4) -------------------结果: (1, 2, 3, 4)
def func(*args):
print(args) #如果传入元组参数,那么元组作为args的单个元素。
func((1,2),(3,4)) -
调用函数有 *
def func(*args): print(args) func(*(1,2,3,4)) #如果*(),实参元组前面有*,那么实参元组内的每个元素都放到形参构成的元组内,即形参 func(*[1,2,3,4]) -----------------------结果: (1, 2, 3, 4) (1, 2, 3, 4)
def func(*args): #函数内print星号和不print星号的区别
print(args)
print(*args)
func(1,2,3,4)
---------结果:(1, 2, 3, 4)
1 2 3 4
-
-
只能用位置传参
def func(*args): print(args) func(1) func(1,2) # args=(1, 2) func((11,22,33,44,55)) # args=((11,22,33,44,55),) func(*(11,22,33,44,55)) # args=(11,22,33,44,55) -----------------------结果: (1,) (1, 2) ((11, 22, 33, 44, 55),) (11, 22, 33, 44, 55)
-
-
**kwargs
-
可以接受任意个数的关键字参数,并将参数转换成字典。
-
调用函数无 **
def func(**kwargs): print(kwargs) func(k1=1,k2="mcw") ------------------------结果: {\'k1\': 1, \'k2\': \'mcw\'}
-
调用函数有**
def func(**kwargs): print(kwargs) func(**{\'k1\':\'v2\',\'k2\':\'v2\'}) # kwargs={\'k1\':\'v2\',\'k2\':\'v2\'} ---------------------------------结果: {\'k1\': \'v2\', \'k2\': \'v2\'}
-
-
只能用关键字传参
-
综合应用:无敌 + 无敌 => 真无敌
def func(*args,**kwargs): print(args,kwargs) func(1,2,3,4,5,k1=2,k5=9,k19=999) func(*[1,2,3],k1=2,k5=9,k19=999) func(*[1,2,3],**{\'k1\':1,\'k2\':3}) func(111,222,*[1,2,3],k11=\'alex\',**{\'k1\':1,\'k2\':3}) ------------------------结果: (1, 2, 3, 4, 5) {\'k1\': 2, \'k5\': 9, \'k19\': 999} (1, 2, 3) {\'k1\': 2, \'k5\': 9, \'k19\': 999} (1, 2, 3) {\'k1\': 1, \'k2\': 3} (111, 222, 1, 2, 3) {\'k11\': \'alex\', \'k1\': 1, \'k2\': 3}
-
5.7、混合传参
def func(a1,*args)
func(1,2,3) 传了1给a1,后面给args
def func(a1,*args,a2) 混搭
func(1,2,3,a2=4)
def func(a1,*args,a2=10) 混搭 a2只能靠关键字来传与上同。
func(1,2,3,a2=4)
def func(a1=2,*args,a2) #混搭 错误方式
func(1,2,3,a2=4)
def func(**kwargs) #传多个键值对到函数,实参为键=值 #万能,传n个关键字参数。并将参数转换
为字典
func(k1=1,k2="s")
def func(**kwargs): #kwargs={k1=1,k2="s"} #传字典到函数内 **字典
print(kwargs)
func(**{"k1":1,"k2":"s"})
-------------结果:
{\'k1\': 1, \'k2\': \'s\'}
def func(**kwargs) #kwargs={k1:{"m":"c"},k2:"s"} #将键值对和字典一起传到函数内,
func(k1={"m":"c"},k2="s")
5.8、传参使用场景总结:
1、我想要简单点的基本传参,用位置传参;
2、我传参想让谁接收,用关键字传参。
3、我没传参想让形参有个默认值,用默认传参;
4、我要传递多个参数,用一个*号的接收;
5、我要传递多个键值对或字典,用两个**接收。
函数:增加代码重用性,可读性。
比如去楼下拿快递,是个函数,告诉他拿**的快递,他就拿到**的快递
6、函数返回值return
1) print 和 return 的区别,print 仅仅是打印在控制台,而 return 则是将 return 后面的部分作
为返回值作为函数的输出,可以用变量接走,继续使用该返回值做其它事。
2)函数需要先定义后调用,函数体中 return 语句的结果就是返回值。如果一个函数没有 reutrn 语句
,其实它有一个隐含的 return 语句,返回值是 None,类型也是 \'NoneType\'。
3)return作用:结束函数调用、返回值
4)终止函数的方法:满足某个条件 return False
成功与不成功返回一个结果。如果不需要打印,用户只需要某个结果,那么让函数返回一个值,让用户
根据返回值做对应的操作。return实现函数返回值。
调用函数,并用变量接收函数的返回值。
6.1使用变量接收返回值:
def xiaoma(): a=1 return a mcw=xiaoma() print(mcw) ------------结果 1
6.2用户根据函数返回值做别的操作。(根据返回值进行通信)
#当小明吃完饭,给我返回1。小明吃完后小马过河找他玩
def xiaoming(arg): a=0 if arg=="吃完": a=1 return a status=xiaoming("吃完") if status==1: print("小马过河去找小明玩") --------------结果: 小马过河去找小明玩
6.3返回多个值的方法:
如果程序需要有多个返回值,则既可将多个值包装成列表之后返回,也可直接返回多个值。如果 Python
函数直接返回多个值,Python 会自动将多个返回值封装成元组。多个值用逗号隔开。
1)python 函数使用 return 语句返回 "返回值",可以将其赋给其它变量作其它的用处
2)所有函数都有返回值,如果没有 return 语句,会隐式地调用 return None 作为返回值
3)一个函数可以存在多条 return 语句,但只有一条可以被执行,如果没有一条 reutrn 语句被执行,同样会隐式调用 return None 作为返回值
4)如果有必要,可以显式调用 return None 明确返回一个None(空值对象)作为返回值,可以简写为 return
5)如果函数执行了 return 语句,函数会立刻返回,结束调用,return 之后的其它语句都不会被执行了
def list_sum(li): sum=0 e_str="" for i in li: e_str+=str(i) sum+=i return sum,e_str li=[1,2,3] mcw=list_sum(li) # 获取list_sum函数返回的多个值,多个返回值被封装成元组 v1,v2=list_sum(li) #此外,也可使用 Python 提供的序列解包功能,直接使用多个变量接收函数返回的多个值。 print(mcw) print(v1,v2) ---------------结果: (6, \'123\') 6 123
6.4return终止循环
def mcw(): #没有return的时候,返回值默认是None,循环正常结束。 for i in range(1,4): print(i) m=mcw() print(m) -------------结果: 1 2 3 None def mcw(): #有return的时候,返回指定的值,并终止函数向后继续执行了。 for i in range(1,4): if i==3: return "终止函数了" print(i) m=mcw() print(m) -------------结果: 1 2 终止函数了
6.5、直接打印返回值
def mcw(): return "魔降风云变" print(mcw())
6.6 for .. else .. 语句 (意外终止情况)
# 表示如果 for 语句段的内容正常循环结果才会执行 else 段的语句,如果 for 在循环过程中时被 break 或者 return 语句意外终止循环,就不会执行 else 段中的语句。
6.7、return可以返回任意类型。
#假如需要函数返回字典,列表等,就可以给函数调用的时候使用。
retrue 一个数据类型。
def func(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8):
return (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
print(func(1,False,None,"mcw",["xiaoma","1"],(1,2),{"name":"xiaoma"},{3,4}))
-------------------结果:
(1, False, None, \'mcw\', [\'xiaoma\', \'1\'], (1, 2), {\'name\': \'xiaoma\'}, {3, 4})
6.8、if判断使用返回值的三种方式:
def func(a1,a2): if a1>a2: return a1 else: return a2 def func(a1,a2): return a1 if a1>a2 else a2 def func(a1,a2): b=a1 if a1>a2 else a2 return b
6.9可利用返回值True和默认的返回值None做函数返回的判断
def func(arg1): if arg1==1: return True print(func(0)) -----------结果: None
6.10其他的返回值,非函数返回值总结
li=[1,2] print(li.append(3)) #没有返回值就是None吗? ---------------结果: None li=[1,2] m=li.append(3) print(m) -----------结果: None a="mcw" a="*".join(a) print(a) ----------------结果: m*c*w
总结:列表所有方法基本上都是返回None,字符串的所有方法基本上是返回新值
7、函数作用域
7.1全局作用域
-
py文件:全局作用域
-
函数:局部作用域
- 变量先创建才能再使用。
- 函数也可以看做一个变量,指向一堆代码
- 作用域中的数据归自己所有,别人访问不到,局部作用域可以继承全局作用域
- 函数调用全局变量,可以使用在函数调用之前的环境变量,但是不可以使用函数调用之后的
-
print(func) 返回的地址
print(func()) 返回调用值 -
a = 1 def s1(): x1 = 666 print(x1) print(a) print(b) b = 2 print(a) s1() a = 88888 def s2(): print(a,b) s1() s2() ---------------------结果: 1 666 1 2 88888 2 666 88888 2
-
总结:
-
一个函数一个作用域,(其他语言很多是一个代码块一个作用域)
-
作用域中查找数据的规则,优先在自己作用域寻找,自己没有就去父集作用域中寻找,父集没有再不断往上层的父集去找。直到全局作用域,再没有就报错。
- 父集无法使用子集的变量。子集可以不断往外层的父集寻找变量
- 1、找变量,本层没有,2、去上一级作用域中,找调用本函数之前最后赋值的那个变量,3、如果到达全局环境变量后还没有就会报错。如果没有到达环境变量,请执行第2步。
-
globla 找到全局 找到后可以给全局变量重新赋值,
nonloacl 找到上级,找到后可以给上级变量重新赋值。 -
作用域每层都是有自己独立的内部空间的,子能继承父,但不能重新赋值父,需要借助global和nonlocal。#思考(不确定的问题):有global和nonlocal找到父所在空间,重新开辟空间进行赋值,否则开辟的是自己所在的空间吗?
-
def func(): x = 9 print(x) func() print(x) #函数内部能使用内部变量,但是函数外部不能使用函数内部变量 -------------结果: 9 Traceback (most recent call last): File "D:/aPython_full目录/小马过河的代码练习/mcwday09.py", line 269, in <module> print(x) NameError: name \'x\' is not defined
-
作用域中查找数据规则:优先在自己的作用域找数据,自己没有就去 "父级" -> "父级" -> 直到全局,全部么有就报错。注意:父级作用域中的值到底是什么?
x = 10 def func(): x = 9 print(x) func() ---------------结果: 9
globla 找到全局 找到后可以重新赋值,
nonloacl 找到上级,找到后后面重新赋值
函数能修改函数外部可变数据类型如列表,集合,字典,但是默认是无法重新赋值的。
如果一定要在函数中给环境变量重新赋值,使用gloabal 变量。子作用域重新赋值全局变量
如果是子函数中使用global重新赋值,改的也是全局
nonloacl改的是父集,上一层的变量。
尽量不要修改全局。会造成代码出现问题
全局变量都是使用大写。局部变量正常的就行了。方便阅读。潜规则。
7.2、global语句
https://www.jb51.net/article/147644.htm
https://blog.csdn.net/weixin_37583747/article/details/81262859
7.3、nonlocal语句
8、lambda函数(匿名函数)
8.1、lambda函数简介
python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
- lambda 只是一个表达式,函数体比 def 简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
8.2、lambda 函数语法
lambda 函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
8.3、
lambda 为了解决简单函数的情况。运算相当于简单函数编写方式。这样函数就相当于一个变量
一行表示,所以不定义变量,使用上一层作用域的变量
变量名=lambda 参数(有无*/**):操作或者函数返回值(返回值可为表达式,为三元运算;表达式有返回的就
作为返回值,否则返回None)
表达式1:
没有参数,只返回指定值
有一个参数,返回表达式
有*和**的参数,举例比如返回*和**长度和
lambda 表达式结合三元运算,返回值部分使用三元运算。
多个lambda放入列表。调用lambda.
9、函数中高级使用 高阶函数
9.1、函数可以作为变量来使用
1) def func(): print("mcw") v1 = func #将函数名赋予一个变量,再给变量加上小括号便能代替原函数名执行这个函数。函数名指 向函数体的内存位置 func() # v1() -------------结果: mcw mcw 由上面那个函数打印可知,函数名赋予给变量后,他们都是指向一个内存地址,函数()代表函数返回值 ,默认为None。 print(type(func),type(func()),func,func()) print(type(v1),type(v1()),v1,v1()) ------------结果: 123 123 <class \'function\'> <class \'NoneType\'> <function func at 0x00A28D20> None 123 123 <class \'function\'> <class \'NoneType\'> <function func at 0x00A28D20> None 2)函数名可以放入列表等数据类型,调用函数时加上小括号 def func(): print(123) func_list = [func, func, func] func_list[0]() -----------结果: 123 def func(): print(123) func_list = [func, func, func] for item in func_list: 循环函数列表并打印函数返回值 v = item() print(v) ----------------结果: 123 None 123 None 123 None 3)函数名作为字典的值来用,(不建议当做键来用,没啥意义)。 def func(): print(123) def bar(): print(666) info = {\'k1\': func, \'k2\': bar} info[\'k1\']() info[\'k2\']() ------------------结果: 123 666 4)容易弄错的案例: def func(): return 123 func_list1 = [func,func,func] func_list2 = [func(),func(),func()] print(func_list1) print(func_list2) info = { \'k1\':func, \'k2\':func(), } print(info) ------------------结果: [<function func at 0x00648D20>, <function func at 0x00648D20>, <function func at 0x00648D20>] #func函数名是指向函数的地址 [123, 123, 123] # func()是函数返回值。这里指定返回值为123 {\'k1\': <function func at 0x00648D20>, \'k2\': 123}
5)综上可知: def func(): print("mcw") v1 = func
函数名实质上就是函数的内存地址。
当我们定义a=1的时候,系统会开辟一块内存空间来保存1,然后用a变量名保存1所在
以上是关于Python基础知识-09-函数的主要内容,如果未能解决你的问题,请参考以下文章