python视频学习笔记8(函数返回值和参数进阶)
如果函数内部有return,并且return后面跟有一个值,就是函数有返回值。可以是变量也可以是字符
如果函数内部有return,后面没有值,表示满足这个函数条件后,函数执行提前结束(后面的不执行)
## 目标
* 函数参数和返回值的作用
* 函数的返回值 进阶
* 函数的参数 进阶
* 递归函
拆包
## 01. 函数参数和返回值的作用
函数根据 **有没有参数** 以及 **有没有返回值**,可以 **相互组合**,一共有 **4 种** 组合形式
1. 无参数,无返回值
2. 无参数,有返回值
3. 有参数,无返回值
4. 有参数,有返回值
> 定义函数时,**是否接收参数,或者是否返回结果**,是根据 **实际的功能需求** 来决定的!
1. 如果函数 **内部处理的数据不确定**,就可以将外界的数据以参数传递到函数内部
2. 如果希望一个函数 **执行完成后,向外界汇报执行结果**,就可以增加函数的返回值
### 1.1 无参数,无返回值
此类函数,不接收参数,也没有返回值,应用场景如下:
1. **只是单纯地做一件事情**,例如 **显示菜单**
2. 在函数内部 **针对全局变量进行操作**,例如:**新建名片**,最终结果 **记录在全局变量** 中
> 注意:
* 如果全局变量的数据类型是一个 **可变类型**,在函数内部可以使用 **方法** 修改全局变量的内容 —— **变量的引用不会改变**
* 在函数内部,**使用赋值语句** 才会 **修改变量的引用**
------------------------------------
def my_print():
print(''nihao')
my_print()
------------------------------------
### 1.2 无参数,有返回值
此类函数,不接收参数,但是有返回值,应用场景如下:
* 采集数据,例如 **温度计**,返回结果就是当前的温度,而不需要传递任何的参数
--------------------------------
def my_pi():
return 3.1415926 #也可以直接返回一个字符串
pi = my_pi()
print(pi)
----------------------------------------
### 1.3 有参数,无返回值
此类函数,接收参数,没有返回值,应用场景如下:
* 函数内部的代码保持不变,针对 **不同的参数 处理 不同的数据**
* 例如 **名片管理系统** 针对 **找到的名片** 做 **修改**、**删除** 操作
---------------------------
def print_info(name):
print(name)
print_info("lili")
---------------------------
### 1.4 有参数,有返回值
此类函数,接收参数,同时有返回值,应用场景如下:
* 函数内部的代码保持不变,针对 **不同的参数 处理 不同的数据**,并且 **返回期望的处理结果**
* 例如 **名片管理系统** 使用 **字典默认值** 和 **提示信息** 提示用户输入内容
* 如果输入,返回输入内容
* 如果没有输入,返回字典默认值
------------------------------------
def my_func(a,b):
ret = a -b
return ret
result = my_func(5,3)
------------------------------
## 02. 函数的返回值
-----------------------------------------------------
def addnum(a,b)
ret = a + b #定义一个变量来记录2个值的求和
return ret #把函数执行结果返回
num= addnum(10,11) #此时来执行addnum这个函数,10和11带入运行上述函数后,收到了返回值;使用一个变量num来记录return的返回值,如果不用可以不定义num,直接执行
print(num)
---------------------------------------------------------------------------------------
2.1 多个return,函数中return后面无结果表示结束掉
--------------------------------------
# 定义一个函数 当执行函数的时候 传入一个分数 可以返回一个字符串 (优 良 中 差)
# 包含多个return
def my_func(score):
# 对分数进行判断
if score >= 90:
return "优"
elif score >= 80:
return "良"
elif score >= 60:
return "中"
elif score >= 0:
return "差"
# 他不会执行 因为在第11行已经执行了return
print("测试")
ret = my_func(89)
print(ret)
def my_func1():
print("开始")
# 只要函数中执行了return 提前结束函数的执行 而且return后面的代码将不再执行(后面的开始1 20 结束都不会执行)
return "3.14"
print("开始1")
return 20
print("结束")
ret = my_func1()
print(ret)
print("测试")
"""
开始
3.14
测试
"""
-----------------------------------------------
# 提出需求 如果调用函数的人 传入的分数小于0 那么就人为传入的分数错误 告知函数的调用者
# 01-作为函数的返回值
# 02-执行的函数提前结束 (为了提高性能考虑)
def my_func(score):
if score < 0:
print("您传入的分数有误!!!")
# 如果小于0,则函数的执行提前结束
return
print("测试")
# 对分数进行判断
if score >= 90:
return "优"
elif score >= 80:
return "良"
elif score >= 60:
return "中"
elif score >= 0:
return "差"
# 只要小于0,则这一段他不会执行 因为在第11行已经执行了return
print("测试")
my_func(-10)
-----------------------------------------------
2.2 一个函数返回多个数据(返回出列表,元组,字典)
-----------------------------------------
# 需求 传入一个人名字 和年龄
# 例如 小明 22
# 通过调用函数后 得到两个字符串 姓名:小明 年龄:22
# 列表
# def deal_name_age(name, age):
# # 处理后 姓名:小明 年龄:22
# new_name = "姓名:%s" % name
# new_age = "年龄:%d" % age
# return [new_name, new_age]
# ret = deal_name_age("小明", 22)
# print(ret[0])
# print(ret[1])
# 字典
# def deal_name_age(name, age):
# # 处理后 姓名:小明 年龄:22
# new_name = "姓名:%s" % name
# new_age = "年龄:%d" % age
# return {"name":new_name, "age":new_age}
#
# my_dict = deal_name_age("小明", 22)
# print(my_dict["name"])
# print(my_dict["age"])
# 元组
def deal_name_age(name, age):
# 处理后 姓名:小明 年龄:22
new_name = "姓名:%s" % name
new_age = "年龄:%d" % age
return new_name, new_age # 如果在函数内部 使用return 返回值1 返回值2,... 默认就是元组类型 不需要写小括号
#
my_tuple = deal_name_age("小明", 22)
print(type(my_tuple))
print(my_tuple[0])
print(my_tuple[1])
## 03. 函数的参数
### 3.1. 不可变和可变的参数
> 问题 1:在函数内部,针对参数使用 **赋值语句**,会不会影响调用函数时传递的 **实参变量**? —— 不会!
----------------------------------------------------------------------------------
下面的例子当中num是个数字,之前说过数字是不可变类型。
第一步glnum标签被贴到99上
第二步开始执行demo,将变量glnum=99以参数的形式传递到函数中,那么num也被贴到99上
第三步开始将num重新贴到100上
结果num=100 glnum=99
-----------------------------------------------------------------------------------------
下面弄个可变类型参数
----------------------------------------------------------------------
demo中增加可变类型参数,列表/字典,numlist
定义全局列表,设置初始值456,并将列表当成实参传递到函数f内部
第一步"gllist应用列表456
第二步 开始执行demo,把gllist引用以参数的形式传递到函数内部,函数内部有numlist来接受,意味着函数内部建立了一个局部变量,并贴在了456上
第三步 函数内部内存中分配小格子记录123,并将numlist从456撕下来贴到123
结果gllist=456 numlist=123
`-------------------------------------------------------------------------------
总结:* 无论传递的参数是 **可变** 还是 **不可变** :只要 **针对参数** 使用 **赋值语句**,会在 **函数内部** 修改 **局部变量的引用**,**不会影响到 外部变量的引用**
> 问题 2:如果传递的参数是 **可变类型**,在函数内部,使用 **方法** 修改了数据的内容,**同样会影响到外部的数据**
调用append方法不会修改列表的引用,只是在列表末尾追加了数字9
#### 面试题 —— `+=`,先相加后赋值
* 在 `python` 中,列表变量调用 `+=` 本质上是在执行列表变量的 `extend` 方法,不会修改变量的引用
``
3.2函数传入关键字参数
------------------------
#定义一个函数
# python是一个弱类型
def my_print(name, age, no):
print("我的名字:%s" % name)
print("我的年龄:%d" % age)
print("学号:%s" % no)
# 调用-> 位置参数
# my_print("小明", 20)
# 关键字参数
# 调用函数的时候使用的是函数的形参名
# my_print(age=22, name="老王")
# my_print(name="老王", age=22)
# 调用函数的时候 使用了位置和关键字参数混合
# 如果混合使用 需要叫位置参数在前 关键字参数再后
# 如果某个参数使用了关键字参数 后面的都需要使用关键字参数
my_print("小明", age=20, no="007")
--------
3.3 函数参数传入缺省参数: 给形参设置了一个默认值
def my_print(name, age=20, no="001") 里面赋值了就是缺省参数
----------------------------
# # 定义一个函数 名字 学号 年龄
# def my_print(name, no, age):
# print("名字:%s" % name)
# print("学号:%s" % no)
# print("年龄:%d" % age)
# print("="*30)
#
#
# # 小明 001 20
# # 小红 002 20
# # 小张 003 20
# my_print("小明", "001", 20)
# my_print("小红", "002", 20)
# my_print("小张", "003", 20)
# 定义一个有缺省参数的函数
# 缺省参数: 给形参设置了一个默认值
# 定义一个函数 名字 学号 年龄
# def my_print(name, no, age=20):
#
# print("名字:%s" % name)
# print("学号:%s" % no)
# print("年龄:%d" % age)
# print("="*30)
# 小明 001 20
# 小红 002 20
# 小张 003 20
# 在调用函数的时候 如果有默认值 可以根据业务需求不传递
# my_print("小明", "001")
# my_print("小红", "002")
# my_print("小张", "003")
# 假如这个my_print的函数打印全班的人的信息 有80% 是20岁 但是 20% 年龄在25-30之间
# 如果执行函数的时候提供实参(本来有20,现在有30来替代20) 那么函数的形参使用实参;如果执行函数的时候没有提供实参 那么形参将使用默认值(缺省参数)
# my_print("老王", "010", 30)
# 在定义函数的时候某个形参使用了缺省参数 那么后面的形参 都需要用缺省参数,比如age是20,后面no也得有缺省参数
def my_print(name, age=20, no="001"):
print("名字:%s" % name)
print("学号:%s" % no)
print("年龄:%d" % age)
print("="*30)
------------------------------------------------
## 04. 函数的递归
> 函数调用自身的 **编程技巧** 称为递归
### 4.1 递归函数的特点
**特点**
* **一个函数** **内部** **调用自己**
* 函数内部可以调用其他函数,当然在函数内部也可以调用自己
**代码特点**
1. 函数内部的 **代码** 是相同的,只是针对 **参数** 不同,**处理的结果不同**
2. 当 **参数满足一个条件** 时,函数不再执行
* **这个非常重要**,通常被称为递归的出口,否则 **会出现死循环**!
示例代码
```python
def sum_numbers(num):
print(num)
# 递归的出口很重要,否则会出现死循环
if num == 1:
return
sum_numbers(num - 1)
sum_numbers(3)
```
![002_递归调用示意图I](media/14993074876434/002_%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%E7%A4%BA%E6%84%8F%E5%9B%BEI.png)
### 4.2 递归案例 —— 计算数字累加
**需求**
1. 定义一个函数 `sum_numbers`
2. 能够接收一个 `num` 的整数参数
3. 计算 1 + 2 + ... num 的结果
```python
def sum_numbers(num):
if num == 1:
return 1
# 假设 sum_numbers 能够完成 num - 1 的累加
temp = sum_numbers(num - 1)
# 函数内部的核心算法就是 两个数字的相加
return num + temp
print(sum_numbers(2))
```
![002_递归调用示意图](media/14993074876434/002_%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%E7%A4%BA%E6%84%8F%E5%9B%BE.png)
> 提示:递归是一个 **编程技巧**,初次接触递归会感觉有些吃力!在处理 **不确定的循环条件时**,格外的有用,例如:**遍历整个文件目录的结构**
5。嵌套函数应用
------------------------------------------
# # 写一个函数打印一条横线
def print_one_line():
print("-"*10)
# 打印自定义行数的横线
def print_lines(num):
for i in range(num):
# 执行函数print_one_line
print_one_line()
print_lines(10)
# 函数求三个数的和
def add3num(a, b, c):
return a + b + c
# 定义函数求三个数的平均值
def average3num(num1, num2, num3):
ret = add3num(num1, num2, num3) # 用上面的求和函数,并且把平均值函数中的参数放进上面的函数
# 把和除以3
return ret / 3
result = average3num(10, 12, 17) #将3个值放入平均值函数,然后值再传入求和函数中
print(result)
------------------------------------------------------
6.拆包# 定义一个列表
# my_list = [1, 3.14, "hello", True]
# 可以获取列表中元素的值 但是可读性不强
# print(my_list[1])
# print(my_list[2])
# 拆包:变量和上面的值是一一对应的
# num, pi, my_str, my_bool = my_list
# print(pi)
# print(my_bool)
# num, pi, my_str, my_bool = [1, 3.14, "hello", True]
# 定义一个元组
# my_tuple = (1, 3.14, "hello", True)
# num, pi, my_str, my_bool = my_tuple
# print(pi)
# 定义一个字典
# my_dict = {"name":"老王", "age": 19}
# ret1, ret2 = my_dict
# 此时得到的是key 字典是无序的
# print(ret1, ret2)
# 一次定义多个变量
# num1 = 10
# num2 = 20
# num3 = 30
# num4 = 3.14
# # 变量名和值是一一对应
# num1, num2, num3, num4 = 10, 20, 30, 3.14
# print(num4)
# 元组 上节课学的返回一个元组
def deal_name_age(name, age):
# 处理后 姓名:小明 年龄:22
new_name = "姓名:%s" % name
new_age = "年龄:%d" % age
# 如果在函数内部 使用return 返回值1 返回值2,... 默认就是元组类型 不需要写小括号
return new_name, new_age
# 下面进行拆包
my_name, my_age = deal_name_age("小明", 20) #本是ret = deal_name_age9 ("小明",20);可直接
print(my_name, my_age)
###拆包 —— 交换两个数字
**题目要求**
1. 有两个整数变量 `a = 6`, `b = 100`
2. 不使用其他变量,**交换两个变量的值**
--------------------------------------------------
#解法1:使用其他的变量
a = 6
b = 100
c = a
a = b
b = c
print(a,b,c)
#解法2:不使用其他的变量
a = 6
b = 100
a = a + b
b = a - b
a = a - b
#解法3:使用到拆包
a = 6
b = 100
a, b = b, a #省略小括号,右边是个元组,其实是a, b = (b, a)
print(a,b)
-----------------------------------------
7.函数的文档说明
# 假设 len函数
# 函数的文档说明 -> 加的文档说明 是python
# help(len)
# len python内置函数 python创建
# 很多的时候需要程序员自己创建
# 自定义一个函数
# def add2num(num1, num2):
# return num1 + num2
#
# # 如果开发写的函数 没有文档说明 用help会打印函数上面的注释
# help(add2num)
# 自定义一个函数
def add2num(num1, num2):
"""
这个函数是用来计算两个数的和的
:param num1: 数字1
:param num2: 数字2
:return: 返回值是两个数字相加
"""
return num1 + num2
# 函数-----使用文档说明和单行注释来进行维护跟踪
def my_func(a, b):
# 文档说明
"""
:param a:
:param b:
:return:
"""
# 单行注释
num = 10
return a + b + num
8.列表推导式
# 定义一个空列表
# my_list = []
# for i in range(1, 101):
# my_list.append(i)
#
# print(my_list)
# 使用列表推导式 快速创建一个列表,相当于上面的方法,前面的i是每次添加进去的
# my_list = [i for i in range(1, 31)]
# print(my_list)
# 反思 得到一个有30个哈哈的列表
# my_list = ["哈哈" for i in range(30)]
# print(my_list)
# 定义一个列表 保存数据[1, 50]之间的偶数
# my_list = []
# for i in range(1, 51):
# # 判断是否是偶数
# if i % 2 == 0:
# my_list.append(i)
#
# print(my_list)
# 列表推导式
# my_list = [i for i in range(1, 51) if i % 2 == 0]
# print(my_list)