Python变量机制深度解析:引用、可变性及作用域实战
本文深入解析Python变量核心机制,涵盖变量与数据的内存分离存储原理、引用传递特性。详细对比int、str等不可变类型与list、dict等可变类型的内存行为差异,并解析局部变量生命周期及全局变量在函数中的访问与修改规则,包括global关键字的正确使用及命名规范建议。
本文详细介绍Python中变量的基础用法及进阶特性,旨在帮助开发者深入理解其内部机制,供参考学习。
- 变量的引用机制
- 可变类型与不可变类型的区别
- 局部变量与全局变量的作用域规则
- 变量与数据在内存中的存储关系
- 函数参数传递与返回值均基于引用传递
1.1 引用的基本概念
在Python语言中,
- 变量名与数据对象是分开存储的
- 实际的数据对象存储在内存的特定位置
- 变量名中保存的是指向该数据对象的内存地址
- 这种记录数据内存地址的行为被称为“引用”
- 可以通过调用id()函数查看变量所指向数据的内存地址
需要注意的是,若变量已存在,再次赋值本质上是修改了该变量的引用指向
- 变量将不再指向之前的数据对象
- 变量将改为指向新赋值的数据对象
1.2 变量引用的具体示例
在Python中,变量名类似于贴在数据对象上的标签
- 定义一个整数变量a并赋值为1
将变量a重新赋值为2
定义整数变量b,并将变量a的值赋给b
此时变量b成为指向数字2的第二个标签
1.3 函数参数与返回值的传递机制
在Python中,函数的实参传递及返回值均通过引用方式进行
def test(num):
print("-" * 50)
print("%d 在函数内的内存地址是 %x" % (num, id(num)))
result = 100
print("返回值 %d 在内存中的地址是 %x" % (result, id(result)))
print("-" * 50)
return result
a = 10
print("调用函数前 内存地址是 %x" % id(a))
r = test(a)
print("调用函数后 实参内存地址是 %x" % id(a))
print("调用函数后 返回值内存地址是 %x" % id(r))
- 不可变类型,内存中的数据不允许被修改:
- 不可变类型包括:int、bool、float、complex、long(仅Python 2.x)
- 字符串类型 str
- 元组类型 tuple
- 可变类型,内存中的数据可以被修改:
- 列表类型 list
- 字典类型 dict
a = 1 a = "hello" a = [1, 2, 3] a = [3, 2, 1]
demo_list = [1, 2, 3]
print("定义列表后的内存地址 %d" % id(demo_list))
demo_list.append(999)
demo_list.pop(0)
demo_list.remove(2)
demo_list[0] = 10
print("修改数据后的内存地址 %d" % id(demo_list))
demo_dict = {"name": "小明"}
print("定义字典后的内存地址 %d" % id(demo_dict))
demo_dict["age"] = 18
demo_dict.pop("name")
demo_dict["name"] = "老王"
print("修改数据后的内存地址 %d" % id(demo_dict))
注意:字典的键(key)只能使用不可变类型的数据
注意事项
- 可变类型的数据修改是通过调用特定方法实现的
- 若给可变类型变量赋值新数据,其引用会指向新数据
- 变量不再指向之前的数据对象
- 变量改为指向新赋值的数据对象
哈希 (hash)
- Python内置有一个名为hash(o)的函数
- 接收一个不可变类型的数据作为参数
- 返回结果为一个整数
- 哈希是一种算法,用于提取数据的特征码(指纹)
- 相同的内容会产生相同的哈希结果
- 不同的内容会产生不同的哈希结果
- 在Python中,设置字典键值对时,会首先对key进行hash计算,以决定如何在内存中存储字典数据,从而方便后续对字典进行增、删、改、查操作
- 字典键值对中的key必须为不可变类型数据
- 字典键值对中的value可以是任意类型的数据
- 局部变量是在函数内部定义的变量,仅限函数内部访问
- 全局变量是在函数外部定义的变量(未定义在特定函数内),所有函数内部均可使用
提示:在其他开发语言中,通常不推荐使用全局变量,因其作用域过大可能导致程序难以维护
3.1 局部变量详解
- 局部变量是在函数内部定义的变量,仅限函数内部访问
- 函数执行完毕后,系统会回收函数内部的局部变量
- 不同函数可定义同名局部变量,彼此互不影响
局部变量的主要作用
- 在函数内部临时保存所需使用的数据
def demo1():
num = 10
print(num)
num = 20
print("修改后 %d" % num)
def demo2():
num = 100
print(num)
demo1()
demo2()
print("over")
局部变量的生命周期
- 生命周期指变量从创建到被系统回收的过程
- 局部变量仅在函数执行时被创建
- 函数执行结束后,局部变量被系统回收
- 在生命周期内,局部变量可用于存储函数内部临时使用的数据
3.2 全局变量详解
- 全局变量是在函数外部定义的变量,所有函数内部均可使用
# 定义一个全局变量
num = 10
def demo1():
print(num)
def demo2():
print(num)
demo1()
demo2()
print("over")
注意:函数执行时处理变量会遵循以下查找顺序:
- 首先查找函数内部是否存在指定名称的局部变量,若存在则直接使用
- 若不存在,则查找函数外部是否存在指定名称的全局变量,若存在则直接使用
- 若均不存在,程序将报错
1) 函数不能直接修改全局变量的引用
- 全局变量是在函数外部定义的变量(未定义在特定函数内),所有函数内部均可使用
提示:在其他开发语言中,通常不推荐使用全局变量,因其作用域过大可能导致程序难以维护
- 在函数内部,可以通过全局变量的引用获取对应数据
- 但不允许直接修改全局变量的引用,即不能使用赋值语句直接修改全局变量的值
num = 10
def demo1():
print("demo1" + "-" * 50)
# 只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
num = 100
print(num)
def demo2():
print("demo2" + "-" * 50)
print(num)
demo1()
demo2()
print("over")
注意:这只是在函数内部定义了一个与全局变量同名的局部变量,并未修改全局变量的值
2) 在函数内部修改全局变量的值
- 若需在函数中修改全局变量,必须使用global关键字进行声明
num = 10
def demo1():
print("demo1" + "-" * 50)
# global 关键字,告诉 Python 解释器 num 是一个全局变量
global num
# 只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
num = 100
print(num)
def demo2():
print("demo2" + "-" * 50)
print(num)
demo1()
demo2()
print("over")
3) 全局变量的定义位置
- 为确保所有函数能正确使用全局变量,应将全局变量定义在其他函数的上方
a = 10
def demo():
print("%d" % a)
print("%d" % b)
print("%d" % c)
b = 20
demo()
c = 30
注意事项
- 若全局变量c在调用函数之后才定义,执行函数时变量尚未定义,程序将报错
代码结构示意图如下
4) 全局变量的命名建议
- 为避免局部变量与全局变量混淆,部分公司制定了开发规范,例如:
- 全局变量名前建议增加g_或gl_前缀
提示:具体格式要求各公司可能有所不同
关于Python相关内容感兴趣的读者可查看本站专题:《Python函数使用技巧总结》、《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》
希望本文所述内容对大家学习Python程序设计有所帮助。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













