day6-基础函数的学习(一)
今日份目录
1.函数的定义
2.函数的返回值
3.函数的参数
4.函数的局部变量与全局变量
5.名称空间与作用域
6.global与nonlocal
7.高阶函数
继续今日份总结!这个总结也晚了,哎,速度还是太慢!
正文开始
随着学习进度的逐渐的加深发现我们的函数体越来重复化越来越严重,太多重复代码,这会让我们的代码的可读性越来越差
1.函数的定义
定义:将一组语句集合通过一个名字(函数名)封装起来,只需要执行,调用其函数名
print sayhi ---->返回内存地址
print sayhi()---->返回函数内的内容
特性:
- 减少重复代码
- 使程序变得可扩展
- 使程序变得易维护
哎,跟着金老师开会儿车,虽然我也不懂怎么用,很多人应该都用过探探或者陌陌这类型聊天交友软件,现在写一下大概的软件的搭建
def tantan(): print('打开手机!') print('打开软件!') print('附件的人!找到附近的人!') print('左滑一下!') print('右滑一下!') print('锁定目标,联系!') print('一起大胆约会吧!相约。。。。。') tantan()#函数的执行者(调用者) #这大概就是使用探探的整个流程了,每次用都是在调用tantan这个函数,就不需要各种重复代码了!
2.函数的返回值
我们运行一个函数,函数外部的代码如果需要获取函数内的执行结果,就可以用函数内的return语句把结果返回
return 默认返回这
def tantan(): print('打开手机!') print('打开软件!') print('附件的人!找到附近的人!') print('左滑一下!') print('右滑一下!') return print('锁定目标,联系!') print('一起大胆约会吧!') tantan() print(666) #返回值 打开手机! 打开软件! 附件的人!找到附近的人! 左滑一下! 右滑一下! 666
我们会发现函数在碰到return就会推出函数的运行,跳出函数的运行,return默认值为空
def tantan(): print('打开手机!') print('打开软件!') print('附件的人!找到附近的人!') print('左滑一下!') print('右滑一下!') print('锁定目标,联系!') print('一起大胆约会吧!') return ('金刚芭比!') print(tantan(),type(tantan())) print(666) #结果 打开手机! 打开软件! 附件的人!找到附近的人! 左滑一下! 右滑一下! 锁定目标,联系! 一起大胆约会吧! 金刚芭比! <class 'str'> 666
def tantan(): print('打开手机!') print('打开软件!') print('附件的人!找到附近的人!') print('左滑一下!') print('右滑一下!') print('锁定目标,联系!') print('一起大胆约会吧!') # return ('金刚芭比!') return [1,100] ret = tantan() print(ret,type(ret)) print(666) #结果 打开手机! 打开软件! 附件的人!找到附近的人! 左滑一下! 右滑一下! 锁定目标,联系! 一起大胆约会吧! [1, 100] <class 'list'> 666
从上面代码可以看出来,在返回单个值得时候,值是什么类型,返回的就是什么类型
def tantan(): print('打开手机!') print('打开软件!') print('附件的人!找到附近的人!') print('左滑一下!') print('右滑一下!') print('锁定目标,联系!') print('一起大胆约会吧!') return ('金刚芭比!','洛天依','初音') ret = tantan() print(ret,type(ret)) print(666) #结果 打开手机! 打开软件! 附件的人!找到附近的人! 左滑一下! 右滑一下! 锁定目标,联系! 一起大胆约会吧! ('金刚芭比!', '洛天依', '初音') <class 'tuple'> 666
根据上面三段代码我们总结出以下几条
- 函数在碰到return就会结束函数,并将值返回函数执行者
- return默认返回值为空
- return返回单个值得时候,值是什么类型,返回值就是什么类型
- return返回多个值得时候,会将多个值用逗号分隔,返回一个元祖
- 函数返回值永远只能返回一个值
3.函数的参数
def tantan(a,b): #函数定义,形参:形式参数 print(a,b) print('打开手机!') print('打开软件!') print('附件的人!找到附近的人!') print('左滑一下!') print('右滑一下!') print('锁定目标,联系!') print('一起大胆约会吧!') return ('金刚芭比!','洛天依','初音') a = 3 b = 2 ret = tantan(a,b)#这个就是函数运行的主体 实参:这个里面的a和b就是实际参数 print(ret,type(ret)) print(666)
3.1 实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值.
以一个学生注册的函数来解释实参
def stu_register(name,age,country,course): print("----注册学生信息------") print("姓名:", name) print("age:", age) print("国籍:", country) print("课程:", course) stu_register("王山炮",22,"CN","python_devops") stu_register("张叫春",21,"CN","linux") stu_register("刘老根",25,"CN","linux")
3.1.1位置参数:按照位置调用顺序,一个一个的调用,传入四个值则则会和下面的调用一一匹配,如果将传入的值调换位置,虽不会报错,显示的内容并不会一样
第一种结果 ----注册学生信息------ 姓名: 王山炮 age: 22 国籍: CN 课程: python_devops #调换姓名和年龄 ----注册学生信息------ 姓名: 22 age: 王山炮 国籍: CN 课程: python_devops
3.1.2关键字参数:既然上面的位置参数更改位置会更改内容,那么就有可以变更位置的参数
stu_register(name="王山炮",age=22,course="python_devops",country="CN") #结果 ----注册学生信息------ 姓名: 王山炮 age: 22 国籍: CN 课程: python_devops 发现我们把参数名称变更位置,函数还是会识别到传入的参数,放在正确的位置
3.1.3混合参数:就是将位置参数和关键字参数混合的输入
#按照关键字参数放在最前面 stu_register(name="王山炮",22,"python_devops","CN") 执行后报错 SyntaxError: positional argument follows keyword argument 翻译过来的意思就是关键字参数不能放在位置参数前面,应该放在位置参数后面
总结一下就是:
- 位置参数,从左到右,一一对应
- 关键字参数,一一对应,不过位置随意
- 混合参数,不过位置参数一定要在关键字参数前面
3.2 形参
形参:只有被调用时才会分配内存单元,调用结束时,释放分配的内存单元,形参只在函数内部有效,函数调用结束时返回主函数后不能再使用该形参
3.2.1位置参数:整体和实参的位置参数一致,默认一一对应
3.2.2默认参数:如果大量的数据都是默认值,则设定默认参数,如果需要更改在去更改
def stu_register(name,age,course,country='CN'): print("----注册学生信息------") print("姓名:", name) print("age:", age) print("国籍:", country) print("课程:", course) stu_register("王山炮",22,"python_devops",) stu_register("张叫春",21,"linux") stu_register("刘老根",25,"linux") #结果 ----注册学生信息------ 姓名: 王山炮 age: 22 国籍: CN 课程: python_devops ----注册学生信息------ 姓名: 张叫春 age: 21 国籍: CN 课程: linux ----注册学生信息------ 姓名: 刘老根 age: 25 国籍: CN 课程: linux
不过有个坑默认参数必须放在位置参数后,要不然也会报错
3.2.2.1默认参数的陷阱
#默认参数指向的是一个容器型数据类型,那么这个数据在内存中永远是同一个 def func1(a,l=[]): l.append(a) return l print(func1(666)) # [666] print(func1(22)) # [666,22] print(func1(33,[])) # [33] #结果 [666] [666, 22] [33]
3.2.3万能参数:俩个形参接收所有实参传递过来的位置参数以及关键参数
在引入万能参数之前,有以下需求
写一个函数:可以传多个列表,把列表里面的所有元素一个一个的添加到args里面。在不使用万能参数的使用前,我们估计会一直用for循环分别添加到一个列表然后在打印
def func(*args): # 在函数的定义时,* 代表聚合。 print(args) #(1,2,3,4,5,6,1,2,3) func(*[1,2,3],*[3,4,5],*[6,7,8])#在函数执行时,*代表打散 #结果 (1, 2, 3, 3, 4, 5, 6, 7, 8) #换其他试一下 func(*[1,2,3],*(1,2,3),*'fdsaf') # 函数的执行(调用)时,* 打散。 #结果 (1, 2, 3, 1, 2, 3, 'f', 'd', 's', 'a', 'f')
# 动态参数 *args **kwargs # def func(*args, **kwargs): # 在函数的定义时,* 代表聚合。 # print(args) # print(kwargs) # func(1,2,3,4,5,'alex',name='taibai',sex='男') # * 的魔性用法。 # 在函数的定义时,* ** 代表聚合。 # 函数的执行(调用)时,* ** 代表打散。 # def func(**kwargs): # print(kwargs) # func(**{"name":'alex'}, **{'age': 46}) def func(*args,**kwargs): print(args) print(kwargs) func(*[1,2,3], *'abfc', **{'name':'alex'}, **{'age': 46}) #结果 (1, 2, 3, 'a', 'b', 'f', 'c') {'name': 'alex', 'age': 46}
关于*的魔性用法在python3.5版本后对于range也开始支持,例子
a,b,*args = [i for i in range(20)] print(a, b, args) #结果 0 1 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
3.2.4 形参的传值顺序
对于形参的传值顺序为(位置参数,*args,默认参数,**kwargs)
def func(a,b,*args,sex='男',**kwargs,): print(a) print(b) print(args) print(sex) print(kwargs) func(1,2,3,4,5,name='alex') #结果 1 2 (3, 4, 5) 男 {'name': 'alex'}
如果位置参数与**kwargs变更位置就会发现,**kwargs包含了所有实参的关键字参数,位置参数也被包含进去了。
总结一下
- 位置参数,从左到右,一一对应
- 默认参数,放在位置参数后面
- 万能参数,能接受实参角度所有的位置参数以及关键字参数
- 形参的顺序,位置参数 *args 关键字参数 **kwargs
4.局部变量与全局变量
函数内外同一个名称的变量,俩个是不一样的,看例子
name = '1A' def change_name(): name ='2b' #函数内的name变更为2b,函数外定义的变量仍没有变更,俩者的内存地址不一样 print('里',name) change_name() print(name)#在函数内部定义的变量称之为局部变量 #结果 里 2b 1A
这样就可以引出全局和局部变量定义
局部变量:在函数结束后,局部变量从内存中清除,俩个函数的局部变量不能互相调用
全局变量:定义在函数外部一级代码的变量,叫全局变量,全局有效
函数内调用变量,优先为局部变量,无则调用全局变量
5.名称空间与作用域
5.1 名称空间
名称空间主要有全局名称空间,局部名称空间,内置名称空间
全局名称空间:存放的是py文件中变量与值的对应关系
局部名称空间:临时存放的是函数体内里面变量与值的对应关系
内置名称空间:内置函数与关键字等等。例如print(), input() break continue
5.2 作用域
全局作用域:内置名称空间,全局名称空间
局部作用域:局部名称空间
加载顺序:加载到内存的顺序
##内置名称空间 ----->全局名称空间 ------>(当函数执行时)局部名称空间
5.3 取值顺序
取值顺序采用就近原则
LEGB原则(局部空间---->父级空间---->全局空间---->内置名称空间)
局部名称空间---->全局名称空间---->内置名称空间
5.4 globals() 与locals()
是俩个python中的内置函数
name = 'alex' age = 46 def func(): name1 = 'barry' age1 = 18 def inner(): print(name1,age1) print(globals()) # 返回一个字典:包含全局作用域所有的内容 print(locals()) # 返回一个字典:当前作用域的所有内容 inner() func() print(globals()) # 返回一个字典:包含全局作用域所有的内容 print(locals()) # 返回一个字典:当前作用域的所有内容
6.global与nonlock的使用
6.1 global : 可以局部声明一个全局变量
age = 46 name = 'xxx' def func(): global name name = 'alex' name = 'barry' func() name = 'qqq' print(name) # 局部作用域不能对全局作用域的变量进行修改,只能引用。
count = 1 def func(): global count count += 1 func() print(count)
总结:global :
- 可以局部作用域声明一个全局变量
- 局部作用域不能对全局作用域的变量进行修改,只能引用,通过设置global可以修改。
6.2 nonlock
# nonlocal : 只在python3x中 存在。 # 1,不能操控全局变量。 # name = 'alex' # def func(): # nonlocal name # print(name) # func() # 内层函数不能对外层函数的变量进行修改,只能引用。 # 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改, # 并且引用的哪层,从那层及以下此变量全部发生改变。 def wrapper(): name = 'alex' def inner(): nonlocal name name += 'b' # print(name) print('1', name) inner() print('2', name) wrapper()
7.嵌套函数与高阶函数
7.1嵌套函数
- 函数内部可以再次定义函数,执行需要被调用
- 同名字的变量会一层一层的向上查找变量
- 注意执行顺序以及变量内外
7.2 高阶函数
定义:变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数被称之为高阶函数
- 接收一个或者多个函数作为参数
- return返回另外一个函数
要抓紧速度了,速度太慢了,加油!