本学习笔记基于 Bilibili视频网站up主—黑马程序员的Python视频教程
链接:https://www.bilibili.com/video/av14184325
变量进阶
1 变量的引用
- 变量 和 数据 都是保存在 内存 中的
- 在python中函数的 参数传递 以及 返回值 都是靠 引用 传递的
引用的概念
- 变量 和 数据 是分开存储的
- 数据 保存在 内存 中的一个位置
- 变量 中保存着数据在内存中的地址
- 变量 中记录数据的地址,就叫做***引用***
- 使用id()函数可以查看变量中保存数据所在的 内存地址
◊注意:如果变量已经被定义,当给一个变量赋值的时候,本质上是 修改了数据的引用
def test(num):
print('在函数内部 %d 对应的内存地址是 %d' % (num, id(num)))
# 1> 定义一个字符串变量
result = 'hello'
print("函数要返回数据的内存地址是 %d" % id(result))
# 2> 将字符串变量返回
return result
# 1. 定义一个数字的变量
a = 10
# 数据的地址本质上就是一个数字
print('a 变量保存数据的内存地址是 %d' % id(a))
# 2. 调用test函数,本质上传递的是实参保存数据的引用,而不是实参保存的数据
# 注意:如果函数有返回值,但是没有定义变量接收
# 程序不会报错,但是无法获得返回结果
r = test(a)
print('%s 的内存地址是 %d' % (r,id(r)))
上述程序的执行结果是:
a 变量保存数据的内存地址是 1908698416
在函数内部 10 对应的内存地址是 1908698416
函数要返回数据的内存地址是 1469963397584
hello 的内存地址是 1469963397584
由结果可知,不论是变量传入函数,还是函数的返回值,只要数据值不变,其地址是不变的。
函数的 实参/返回值 都是是靠 引用 来传递来的
2 可变和不可变类型
- 不可变类型,内存中的数据不允许被修改:
- 数字类型 int, bool, float, complex, long(2.x)
- 字符串 str
- 元组 tuple
- 可变类型,内存中的数据可以被修改:
- 列表 list
- 字典 dict
| 注意:字典的 key 只能使用不可变类型的数据
使用方法对可变类型的变量进行修改,不会改变其地址
哈希hash
- python中内置有一个 hash()的函数
- 接收一个 不可变类型 的数据作为 参数
- 返回 结果是一个 整数
- 哈希 是一种 算法,其作用就是提取数据的 特征码(指纹)
- 设置字典的键值对时,会首先对 key 进行 hash来决定如何在内存中保存字典的数据,以方便后续对字典的操作:增、删、改、查
3 局部变量和全局变量
局部变量:在函数内部定义的变量,只能在函数内部使用
全局变量:在函数外部定义的变量,所有函数内部都可以使用
** 注意!函数执行时处理变量的过程:**
- 首先查找 函数内部 是否存在指定名称的 局部变量,如果有就直接使用
- 如果没有,查找 函数外部 是否存在 指定名称的 全局变量,如果有就直接使用
- 如果仍没有,程序报错
局部变量
局部变量的生命周期:
def demo1():
# 定义一个局部变量
# 1> 变量的出生:执行了下方代码后,才会被创建
# 2> 死亡:函数执行结束后被系统回收
num = 10
print('在demo1函数内部的变量是 %d' % num)
demo1()
- 局部变量 是在 函数内部 定义的变量,只能在函数内部使用
- 函数执行结束后,函数内部的局部变量会被系统回收
- 不同的函数可以定义相同名字的局部变量,但是彼此之间不会产生影响
全局变量
- 全局变量是在 函数外部定义 的变量,所有函数都可以使用这个变量
- 在函数内部,可以 通过全局变量的引用获取对应的数据
- 无法在函数内部直接修改全局变量的值
在函数内部修改全局变量的值
如果在函数内部需要修改 全局变量 的值,使用 global关键字:
# 全局变量
num = 10
def demo1():
# 想要修改全局变量的值 - 使用global声明一下变量即可
# global关键字 会告诉解释器后面的变量是一个全局变量
global num
num = 99
print('demo1 ==> %d' % num)
def demo2():
print('demo2 ==> %d' % num)
demo1()
demo2()
程序输出的结果:
demo1 ==> 99 demo2 ==> 99
在编写代码时,我们需要在代码一开始就 定义完成全局变量,否则若在执行函数时变量没有定义,程序就会报错。
代码结构示意图 |
---|
shebang |
import模块 |
全局变量 |
执行代码 |
全局变量命名的建议:
全局变量名之前应该加g_
或 gl_
的前缀
4 函数的返回值
利用 元组 返回多个返回值:
def measure():
"""测量温度和湿度"""
print('begin...')
temp = 39
print('over...')
wetness = 50
# 元组可以包含多个数据,可以让函数返回多个值
# return (temp,wetness)可以省略括号
return temp,wetness
result = measure()
print(result)
# 需要单独的处理温度或者湿度
# 如果函数返回的类型是元组,同时希望单独的处理元组中的元素
# 可以使用多个变量,一次接收函数的返回结果
# 注意:使用多个变量接收结果时,变量的个数应该和元组中元素的个数保持一致
gl_temp, gl_wewtness = measure()
print(gl_temp)
print(gl_wewtness)
交换两个变量的值:
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
print(a)
print(b)
5 函数的参数 进阶
不可变 和 可变 的参数
无论传递的参数是 可变(list、dict) 还是 不可变(数字),
只要针对参数使用赋值语句,会在 函数内部 修改 局部变量 的引用,不会影响到 外部变量 的引用。
如果传递的参数是可变类型(list、dict),在函数内部,使用 方法 修改数据的内容,同样会影响到外部实参。
def demo(num_list):
print('函数内部的代码')
# 使用方法修改列表的内容
num_list.append(9)
print(num_list)
print('函数执行完成')
gl_list = [1,2,3]
demo(gl_list)
print(gl_list)
这段代码的输出结果是:
函数内部的代码 [1, 2, 3, 9] 函数执行完成 [1, 2, 3, 9]
例外情况: +=
“+=” 符号
- 对于数字变量而言,是赋值操作,即将左右两边的变量相加再赋值给左边的变量
- 对于列表变量而言,是方法操作,本质上是在调用列表的 extend方法,即:左边.extend(右边)
O因此,在函数内部对传入的参数使用 += 符号时,若传入的参数是数字变量,则对外部实参没有影响;如果传入的参数是 列表变量,则会对外部实参有影响。
def demo(num,num_list):
print('begin')
#对 数字变量使用 +=
# num = num + num
num += num
# 对列表变量使用 += 不是 相加再赋值 !
# 本质上是在调用列表的 extend 方法
# num_list.extend(num_list)
num_list += num_list
print(num)
print(num_list)
print('over')
gl_num = 9
gl_list = [1, 2, 3]
demo(gl_num,gl_list)
print(gl_num)
print(gl_list)
这段代码的输出结果是:
begin
18
[1, 2, 3, 1, 2, 3]
over
9
[1, 2, 3, 1, 2, 3]
缺省参数
具有默认值的参数就是 缺省参数
指定函数的缺省参数:
- 在参数后使用赋值语句,可以指定参数的缺省值(默认值)
def func(name, gender=True)
- 缺省参数的注意事项:
- 在函数的参数列表中,带有默认值的缺省参数必须放在列表末尾
错误示例:def func(name, gender=True, title)
- 调用带有多个缺省参数的函数时,需要指定参数名来赋值
func('小明',gender=False)
- 在函数的参数列表中,带有默认值的缺省参数必须放在列表末尾
def print_info(name, title='学生', gender=True):
"""
:param tiele: 职位
:param name: 班上同学的姓名
:param gender:True 男生 False 女生
"""
gender_text = '男生'
if not gender:
gender_text = '女生'
print('[%s]%s 是 %s' % (title, name, gender_text))
print_info('小明')
print_info('小美',gender = False)
6 多值参数
有时可以能需要函数处理的参数的个数是不确定的,此时就可以使用多值参数
python中有 两种 多值参数:
- 参数名前增加 * 可以接收 元组
- 参数名前增加 ** 可以接收 字典
一般在给多值参数命名时,习惯使用以下两个名字
- *args – arguments变量的缩写
- **kwargs – keyword键值对的缩写
多值参数案例:
def sum_numbers(*args):
num = 0
print(args)
for n in args:
num += n
return num
result = sum_numbers(1, 2, 3, 4, 5)
print(result)
这段代码的输出结果是:
(1, 2, 3, 4, 5)
15
元组和字典的拆包:
在调用带有多值参数的函数时,如果希望
- 将一个 元组变量,直接传递给 args
- 将一个 字典变量,直接传递给 kwargs
就可以使用 拆包,简化参数的传递:- 在元组变量前增加 *
- 在字典变量前增加 **
7 函数的递归
一个函数 在内部调用自己 就是递归。
代码特点:
函数内部的 代码 时相同的,只是针对参数的不同,处理的结果不同
当 参数 满足一个条件时,函数不再执行(就是 递归的出口)
下面为两个函数递归调用的例子:
def sum_number(num):
print(num)
#递归的出口:当参数满足某个条件时,不再执行函数
if num == 1:
return
# 自己调用自己
sum_number(num - 1)
sum_number(3)
# 定义一个函数计算1 + 2 + ... + num 的结果
def sum_numbers(num):
# 1. 出口
if num == 1:
return 1
# 2. 数字的累加
temp = sum_numbers(num - 1)
return num + temp
result = sum_numbers(100)
print(result)