一.理解
函数可以简单的理解为:存储以一个功能为一个小型模块的集合
可以解决的问题:
1. 重复的代码多,不好看, 代码冗余
2. 不好维护,不好扩展
二.函数的使用原则:先定义在使用
注意:函数保存的是一个功能,而变量保存的是一个数据
变量名代表一个内存空间,这个内存空间存了数据
函数名代表一个内存空间,这个内存空间存了代码
三.函数的表达方式:
def 函数名() #定义函数
代码1
return 返回值
函数名() #为调用函数
四.函数的深入分析:
1.函数在定义的时候发生了什么?
1).在内存空间开辟了一个空间
2).将代码放到这个内存中去
3).将这个内存地址绑定给这个函数名
2.调用函数的本质是:内存地址()#表示内存地址保存的代码
3.区分函数名和函数名()的区别:
函数名 就表示这个函数的内存地址
函数名() 表示运行这个函数绑定的内存里面的代码,并得到这个返回值
4.扩展:
1).写在函数里面的代码,只要不运行函数就不会运行,但是语法错误会出现报错
2).函数分为内置函数和自定义函数
a.内置函数就是python写好的函数Eg:print()....
b.自定义函数就是人为写入并且保存
五.函数中的参数:
1.定义函数括号内的叫做形式参数,简称形参 类似于 变量名
调用函数括号内的叫做实际参数,简称实参 类似于 变量值
调用函数的时候,就相当于Python自动的将你的调用函数括号内的实参自动的
绑定给了定义函数括号内的形参了
形参和实参有个基本的原则:从左到右,一一对应,不多不少
2.分类:
1).位置参数:形参和实参一样的,按照位置来的
2).默认参数
在定义函数的括号内,也就是形参的一种分类,即将形参输为"参数名=值"的形式
再调用函数时,如果你不传递这个实参,这个就绑定默认的值,如果你传递就绑定传递的值
a.好处:
有一个参数一般都是特定的值,就可以做成默认参数,你在调用的时候,就不用传参
3).关键字参数:
再调用函数的时候指名道姓,也就是实参一种
Eg:函数名(参数名1=值1,参数名2 = 值2,...)#可以打乱顺序
3.可变长度参数:
在定义函数的括号内,也就是形参
如果一个形参前面有一个*,那么这个形参就可以接受任意多个位置参数,
组成一个元祖
为了规范,我们通常将这个形参叫做args
如果一个形参前面有两个*,那么这个形参就可以接受任意多个关键字参数,
组成一个字典
为了规范,我们通常将这个形参叫做kwargs
同时有*args,**kwargs 就表示可以接受任意多个任意形式的参数了
4.书写顺序
1).定义函数的括号内:
位置参数,默认参数,*args,**kwargs
2).调用函数:
位置参数,关键字参数
5.返回值:
1.关键字为 return #这个关键字只能出现在函数里面
2.作用:
1).函数里面的代码只要执行到了这个return ,立即退出这个函数
2).作为返回值
3.函数里面没有写return 自动在最后 默认就会给你 return None
4.return 后面可以没有数据 如果没有数据,默认就会给你return None
5.return 后面可以只写一个数据(任意数据类型都可以)。默认是元组的形式
6.return 后面可以写多个数据(任意数据类型都可以),每个数据之间用","号隔开。是元组的形式
注意:意味着只要是个函数,肯定都有返回值
六.名称空间和作用域:
1.名称空间/名字空间:
1).定义:
存放名字的空间 即存放名字和数据绑定关系的地方
2).意义:
不同的空间可以存放相同的名字,名字相同不会冲突
3).类别:名称空间是对栈区的划分
a.内置名称空间
伴随python解释器的启动就产生,python解释器关闭就会回收了
因此是第一个被加载的空间,用来存放一些内置的名字,比如说内置函数名
input print len.....
b.全局名称空间
伴随Python代码的执行就产生,执行完毕就回收了
是第二个被加载的空间
存放的名字:只要不是局部名称空间的的,也不是内置的,
剩下的名字都存放在这个全局名称空间中
存活周期:执行Python程序就产生,执行结束就回收
c.局部名称空间
存放的名字:在调用函数时,运行函数体内部的代码产生的名字
存活周期:在调用函数的时候存活,函数调用完毕了就回收了
4).名称的加载顺序
内置名称空间》》》全局名称空间》》》局部名称空间
5).名称的销毁顺序
内置名称空间《《《全局名称空间《《《局部名称空间
2.作用域: 名字起到作用的范围
1).全局作用域
内置名称空间,全局名称空间中的名字都是全局作用域
1. 全局存活
2. 全局有效:在你的文件中的任意一个地方都可以使用这个名字
2). 局部作用域
局部名称空间中的名字就是局部作用域
1. 临时存活
2. 局部有效:只在自己这个局部内起作用
3.名字的查找顺序
一个名字要想被查找到,从当前所在的位置一层层往前找
即:局部名称空间==>全局名称空间==>内置名称空间
且一个名字必须从这三个空间中找到,找不到就报错 NameError
4.优先级:如果名字已经找到那么就不会在往下查找了
5.global 关键字
在函数内 一个名字前面加了 global 之后,这个名字就会变成
全局的名字,这个名字的作用域就是全局了
本质:修改名字的内存地址从而使作用域发生改变
拓展:
1).globals() 得到所有的全局作用域中的名字 是个字典
2).nonlocal 如果一个函数里面又定义函数(函数的嵌套)然后里面的这个函数写了
"onlocal 名字" 就表示将外层的函数的名字改变(非全局),但外层函数必须有这个名字
3).locals() 如果这个写在局部里面,就表示得到这个局部作用域中的名字,是个字典
如果这个写在全局里面,就表示得到这个全局作用域中的名字,是个字典
闭包:
def a(x):
def b():
pass
return b
# 1. 在全局可以使用局部作用域里面的函数
# 2. 得到了一种新的为函数体传参的方式
七.装饰器:用来给函数增加功能函数
1.开放封闭原则:
开放:对功能的扩展是开放的
封闭:对代码的修改是封闭的,即定义阶段和调用阶段的代码都不能改动,
但是你的功能还是要增加,即功能必须增加,源代码不能改动
2.对于装饰器 我们需要记住的是定义装饰器的语法以及如何使用装饰器
使用装饰器,可以给函数增加功能或者实现控制
定义装饰器,你的装饰器要写在函数的前面,不然就用不到这个名字
3.装饰器的表达方式:
def 函数名1(形参名):
def 函数名2(*args,**kwargs):
变量 = 形参名(*args,**kwargs)
return 变量
return 函数名2
4.使用装饰器:在需要增加功能的函数上方写"@函数名1"就好
八.扩展点
1. def a(b,c):
print(b,c)
a(*[1,2]) # 调用函数的时候,数据前面加了* 炸开
a(**{'c':3,'b':5}) # 调用函数的时候,数据前面加了* 炸开
2.函数的完整语法:
def 函数名(参数):
'''函数的说明'''
#任意符合语法规范的代码
return
Eg:def add(a,b):
'''
这个函数是实现什么功能的
:param a: 描述这个参数的
:param b: 描述这个参数的
:return: 描述返回值
'''
return a+b
print(add(1, 3))
了解点:如何查看函数的说明
第一种方式:help(函数名)
help(add)
第二种方式: print(函数名.__doc__)
print(add.__doc__)