一、认识函数
不使用函数的问题:
1、同样的功能,相同的代码需要重复写很多次;
2、当功能发生改变了,需要修改多处代码。
怎么解决这些问题:使用函数!
1、函数的定义
- a.函数:就是对实现某一特定功能的代码段的封装
- b.分类
-
函数可以分为内置函数和自定义函数
-
内置函数:
- Python已经声明好了,程序员直接调用的函数,如:print函数、input函数、max函数、min函数等等
- 内置函数相当于已经造好的机器 程序员只需要知道机器的功能和使用方法
-
自定义函数:
- 程序员自己声明,自己实现功能的函数,可以提供给别人用,也可以自己用
- 相当于自己设计和创建机器
-
2、函数的声明
a.语法:
def 函数名(形参列表):
函数说明文档
函数体
b.说明:
def - Python中声明函数的关键字
函数名 - 自己命名
要求:标识符,不能是关键字
规范:PEP8 名字中的字母小写,多个单词之间用下划线隔开
见名知义(见到函数名,大概知道函数的功能)
() - 固定写法
形参列表 - 形参名1, 形参名2, 形参名3...(可以有一个参数,也可以 有多个参数,也可以没有参数)
形参的作用:从函数外部向函数内部传递数据
: - 固定写法
函数说明文档 - 用来对函数的功能进行说明的注释,这个注释需要使用三个双引号引起来
函数体 - 实现函数功能的代码段
c.初学者函数声明的步骤
- 第一步:确定函数的功能
- 第二步:根据函数的功能,确定函数名
- 第三步:确定参数 看实现函数的功能,需不需要额外的数据,需要几个数据,就需要几个参数
- 第四步:实现函数的功能
- 第五步:确定返回值
3、函数的调用
(重点)函数在声明的时候不会执行函数体,只有在调用的时候才会执行。
a.语法:
函数名(实参列表)
b.说明:
函数名 - 必须是已经声明过的函数
() - 固定写法
实参列表 - 实参就是给形参赋值(需要传递给函数内部的数据)
目前,形参有多少,实参就需要多少个
二、函数的调用
函数在声明的时候不会执行函数体 只有在调用函数的时候才会执行函数体
1、函数的调用过程(重点!)
a.物理过程
- 第一步:回到函数声明的位置
- 第二步:用实参给形参赋值(传参)
传参一定要保证每个形参都有值 - 第三步:执行函数体
- 第四步:获取返回值
- 第五步:回到函数调用的位置接着往后执行
b.调用函数的过程是一个压栈的过程
- 当函数调用的时候,系统会自动的在内训中栈区间开辟空间,存储函数调用过程中产生的数据(这儿的数据包括参数和在函数中声明的变量)
- 当函数调用完成后,对应的内存空间会自动销毁
对内存的一些补充:
内存分为:栈区间和堆区间
栈区间:系统自动开辟、自动释放
堆区间:原则上手动开辟、手动释放
目前基本上只有C语言支持程序员手动开辟和释放堆区间内存
所有的变量都是存在栈里面,所有的数据都是存储在堆里面
函数调用的时候在栈区间:在栈区间存储函数的参数,函数中声明的变量
当函数调用结束的时候,这个栈区间开辟的空间会自动销毁
三、函数的参数
1、根据实参分为位置参数和关键字参数
- a.位置参数
让实参的位置和形参的位置一一对应 - b.关键字参数
实参以“形参名=值”的形式来传参 - c.位置参数和关键字参数混合使用
前提:保证每个参数都有值,还要保证位置参数在关键字参数的前面
2、从函数声明的角度又有:参数默认值 不定长参数 参数类型说明
- a.参数默认值
- 声明函数的时候可以给参数设置默认值,语法:参数名 = 默认值
- 有默认值的参数放在没有默认值的参数的后面
- 如果函数声明的时候参数有默认值,调用函数的时候,有默认值的参数可以不用赋值
- 如果由的参数有默认值,有的参数没有默认值,有默认值的参数一定要放在没有默认值参数的后面
- 注意:设置默认值除了可以给参数一个默认的值,也可以对参数的类型进行说明。
3、不定长参数
- a.在声明函数的时候,参数名前加一个* 会将这个参数变成元组,来获取多个实参的值(通过位置参数调用)。
- 在调用参数是不定长参数的函数的时候,不定长参数对应的位置,可以传任意个实参。
- b.在声明函数的时候,参数名前加两个* 会将这个参数变成字典(必须使用关键字参数传参)。
- 如果是调用不定长关键字参数(参数名前加了两个*) 调用的时候关键字可以随便命名。
- C.一个*和两个*一起使用 -> 用来表示不定长参数,调用的时候更灵活,可以用位置参数传参,也可以用关键字参数传参,也可以两个一起用。
- 要求:一个*的参数要放在两个*参数的前面。
4、参数类型说明
参数类型说明,只是对参数类型进行提示,不能限制类型
说明方式有两种:
- a.设置默认值
- b.参数名:类型名
def func(a: int, b=’’): - 注意:类型说明除了说明类型以外,还可以做相应类型对应的语法提示。
四、函数的返回值
1、返回值
- a.函数的返回值就是return关键字后面表达式的值,就是函数调用表达式的值。
- b.Python中所有的函数都有返回值,默认是None。
- return - 关键字,用来返回函数的返回值,并且结束函数(当函数在执行的过程中遇到了return 函数直接结束);如果函数体中没有return 函数会在函数体执行完成后将None作为返回值。
- 函数调用表达式 - 调用函数的语句,当函数调用完成后,函数调用表达式的结果就是函数的返回值。
- 返回值的作用:就是将在函数内部产生的数据传递到函数的外部防止在函数调用完成后被销毁。
- 什么时候使用返回值:如果实现函数的功能会产生新的数据,一般都会将这个数据返回。
2、同时返回多个值
Python的函数支持返回多个值
return 返回值1, 返回值2, 返回值3… - 实质是以元组的形式返回
五、返回值的应用
返回值能做的事情,函数调用表达式都可以做。
- 用函数调用表达式给变量赋值。
- 通过函数调用表示式使用相应的方式。
- 将函数调用表达式作为容器的元素,函数的参数,函数的返回值。
六、匿名函数
匿名函数还是函数,除了声明的语法以外,函数其他的语法,匿名函数都支持。
1、匿名函数的声明
- a.语法:
函数名(变量) = lambda 参数列表: 返回值 - b.说明:
- 函数名 - 变量名
- lambda - 关键字
- 参数列表 - 和普通函数的参数列表的作用于要求一样
- 返回值 - 相当于普通函数return关键字后面的表达式
- 注意:匿名函数中,冒号后面的语句属于函数体,在声明的时候不会执行;并且匿名函数的调用和普通函数一模一样。
补充:Python中的三目运算符
- a. C语言中的三目运算符:条件语句?值1:值2 - 条件语句为True 整个表达式结果为值1,否则是值2。
- b. Python中的三目运算符:值1 if 条件语句 else 值2 - 条件语句为True 整个表达式结果为值1,否则是值2。
七、变量的作用域
1、变量的作用域
变量在程序中能够使用的范围
2、全局变量
- a.声明在函数或者类的外部的变量都是全局变量
- b.全局变量的作用域:是从变量声明开始到整个py文件结束,任何位置都可以使用(作用域:从声明开始到文件结束)
3、局部变量
- a.声明在函数或者类的里面的变量都是局部变量
- b.局部变量的作用域:在函数中:从声明开始到函数结束,任何位置都可以使用(作用域:从声明开始到函数结束)
4、global的使用
global关键字只能在函数中使用,作用是用来在函数中声明一个全局变量
语法:
- global 变量名
- 变量名 = 值
5、nonlocal
nonlocal关键字只能在函数中使用
当需要在局部的局部中修改局部变量的值,就使用nonlocal
语法:
- nonlocal 变量
- 变量名 = 值
示例:
def func1():
# 声明一个局部变量a2
a2 = 'abc'
# python中函数可以声明函数
def func11():
nonlocal a2
a2 = 'python'
print('func11-a2:', a2)
# a3的作用域在func11中
a3 = 111
func11()
print('func1-a2:', a2)
func1()
补充:Python中数据是否销毁的方案:看是否有变量将这个数据的地址保存。
八、函数作为变量
Python中声明函数其实就是声明一个类型是function的变量,函数名其实就是变量名。
1、匿名函数的函数名
函数名作为变量除了可以用来调用函数获取返回值以为,普通变量能做的它都能做。
普通函数能做的:
a.让一个变量给另个变量赋值
b.将变量作为列表的元素或者字典的值
c.作为函数的参数
2、实参的高阶函数
将函数1作为实参,传递给函数2 这儿的函数2就是一个高阶函数(实参高阶函数)
应用:sort max min 函数都是高阶函数
sort()函数:
def sort(self, key=None, reverse=False)
- key - 确定排序的时候以什么值为标准来排序(默认情况下直接以列表的元素的大小为标准来排序)
需要传一个函数(这个函数必须有一个参数和一个返回值 并且这儿的参数是列表的元素) - reverse - 是否降序排序 需要传一个bool值
max()函数:
# print(max([(‘a’, 10), (‘b’, 30), (‘c’, 20)], key=lambda tup1: tup1[1]))
3、变量作为函数的返回值
返回值是函数的函数,也叫高阶函数(返回值高阶函数)