语法进阶
变量的引用
- 变量和数据都保存在内存中
- Python 中函数的参数传递以及返回值都是靠引用传递的
引用的概念
Python 中
- 变量和数据分开存储
- 数据保存在内存中的一个位置
- 变量中保存着数据在内存中的地址
- 变量中记录数据地址的动作就叫引用
id()
函数可以查看变量中保存数据的内存地址
如果变量已经被定义,当给一个变量赋值的时候,本质上是修改了数据的引用
- 变量不再对之前的数据引用
- 变量改为对新赋值的数据引用
函数的参数和返回值的传递
Python 中,函数的实参 / 返回值都是靠引用传递的
- 调用函数,本质上是传递的实参 / 返回值保存数据的引用,而不是实参保存的数据
- 如果不定义变量接收函数的返回值,程序不会报错,但是无法获得返回结果
可变类型不可变类型
- 不可变类型,内存中的数据不允许被修改
- 数字类型
int
,bool
,float
,complex
- 字符串
str
- 元组
tuple
- 数字类型
- 可变类型,内存中的数据可以被修改
- 列表
list
- 字典
dict
字典的key
只能使用不可变数据类型
- 列表
局部变量和全局变量
局部变量
- 局部变量是在函数内部定义的变量,只能在函数内部使用
- 函数执行结束后,函数内部的局部变量,会被系统回收
- 局部变量的生命周期
- 生命周期是变量从被创建到被系统回收的过程
- 局部变量在函数执行时才会被创建
- 局部变量在生命周期内,可以用来存储函数内部临时使用到的数据
全局变量
- 全局变量是在函数外部定义的变量,所有函数都可以使用
- 其他开发语言中大多不推荐使用全局变量
- 不允许在函数内部修改全局变量
- 在函数内部重新赋值,只是定义了一个局部变量
- 希望修改全局变量的值 使用
global
声明变量即可 - 应该把模块中的所有全局变量定义到所有函数上方
- 全局变量命名前方应加
g_
或gl_
等与局部变量区分 - 如果局部变量和局部变量名称相同,
pycharm
会在局部变量下方显示灰色虚线
参数和返回值
函数根据有没有参数和有没有返回值可以自由组合,共 4 种
- 无参数,无返回值
- 无参数,有返回值
- 有参数,无返回值
- 有参数,有返回值
- 如果函数内部处理数据不确定,可以将外界数据以参数形式传递给函数
- 如果希望函数执行完成后,向外界汇报结果,可以增加返回值
函数的返回值 - 多个返回值
- 元组可以包含多个数据,因此可以使用元组让函数一次返回多个值
- 如果函数返回的结果是元组,小括号可以省略
- 如果函数的返回值类型是元组,需要单独处理元组中的元素可以使用多个变量,一次接收函数的返回结果
- 注意:使用此方法,变量的个数应该和元组中元素的个数保持一致
问题:交换两个变量的值?
a = 6
b = 100
# 1. 使用其他变量
# c = a
# a = b
# b = c
# 2. 不使用其他变量
# a = a + b
# b = a - b
# a = a - b
# 3. Python 专有
# a, b = (b, a)
# 元组小括号可省略
a, b = b, a
print(a)
print(b)
函数的参数
不可变和可变参数
- 在函数内部,针对参数使用赋值语句不会影响调用函数时传递的实参变量
- 无论传递的参数是可变还是不可变
- 在函数内部,针对参数使用赋值语句,不会修改外部实参变量
def demo(num, num_list):
print("函数内部的代码")
# 在函数内部,针对参数使用赋值语句,不会修改外部实参变量
num = 100
num_list = [1, 2, 3]
print(num)
print(num_list)
print("函数执行完成")
gl_num = 99
gl_list = [4, 5, 6]
demo(gl_num, gl_list)
print(gl_num)
- 如果传递的参数是可变类型,在函数内部,使用方法修改了数据的内容,同样会影响到外部数据
def demo(num_list):
print("函数内部代码")
num_list.append(9)
print(num_list)
print("函数执行完成")
gl_list = [1, 2, 3]
demo(gl_list)
print(gl_list)
问题:-- +=
在 Python 中,列表变量调用 +=
本质上是在执行列表变量的 extend
方法,不会修改变量的引用
缺省参数
- 定义函数时,可以给某个参数指定一个默认值,具有默认值的参数就叫做缺省参数
- 带有默认值的缺省参数必须在参数列表末尾
- 如果有多个缺省值,需要指定参数名
多值参数
- 有可能需要一个函数能够处理的参数个数是不确定的,这时使用多指参数
- Python 中有两种多值参数
- 参数名前增加一个
*
,可以接收元组 - 参数名前增加两个
*
,可以接收字典
- 参数名前增加一个
- 一般在给多指参数命名时,习惯使用以下两个名字
*args
-- 存放元组参数,前面一个*
**kwargs
-- 存放字典参数,前面两个*
args
是arguments
的缩写,有变量的含义kw
是keyword
的缩写,kwargs
可以记忆键值对参数
案例:计算任意多个数字的和
def sum_nums(*args):
num = 0
# 循环遍历
for n in args:
num += n
return num
result = sum_nums(1, 2, 3, 4, 5)
print(result)
- 元组和字典的拆包
- 在调用带有多值参数的函数时,如果希望
- 将一个元组变量,直接传递给
args
- 将一个字典变量,直接传递给
kwargs
- 可以使用
拆包
,简化参数的传递,拆包的方式是:- 在
元组
变量前,增加一个*
- 在
字典
变量前,增加两个*
- 在
递归
递归:函数调用自身
递归的特点
- 一个函数内部调用自己
- 函数内部可以调用其他函数,也可以在内部调用自己
代码特点
- 函数内部的代码是相同的,只是针对参数不同,处理的结果不同
- 当参数满足一个条件时,函数不再执行
- 被称为递归的出口,否则会造成死循环
案例 -- 计算数字累加
- 定义一个函数
sum_numbers
- 能够接受一个
num
的整体参数 - 计算
1 + 2 ... num
的结果
def sum_numbers(num):
# 1. 出口
if num == 1:
return 1
# 2. 数字累加 num + (num - 1)
# 假设 sum_numbers 能处理 1到 num -1 的累加
temp =sum_numbers(num - 1)
return num + temp
result = sum_numbers(100)
print(result)