彻底理解python中函数内赋值操作和对象的可变性
来源:互联网 发布:西部世界解析 知乎 编辑:程序博客网 时间:2024/05/19 18:41
一.函数内赋值操作
1.API中术语
1.--- 4.6. Defining Functions实参在传递时会被引入被调函数的局部符号表
2.--- 4.6. Defining Functions
函数中所有变量的赋值会把值存储在局部符号表中
引用变量时查找顺序: 当前局部符号表 --> 外层封闭函数局部符号表 --> 全局符号表 --> 内置符号表
3.--- 4.2. Naming and binding
在块内被绑定的变量是该块内的局部变量
在模块级被绑定的变量时全局变量
如果一个变量在某块内使用,但未在该块内定义,该变量是自由变量
def f1(a):
print(a)
b = 3
f1(b)
1.b = 3,b在模块级绑定,即b是全局变量,把值存储在全局符号表
2.f(b)调用函数f(b),实参b被引入函数f1的局部符号表
1.函数块内赋值b = a = int型对象3的地址值,存储在该函数的局部符号表中
3.print(a)引用变量a,在函数f1的局部符号表找到a的值,根据该值访问int型对象3
-------------------------------------------------------------------------------------------------------------
def f1(a):
a = 4
print(a)
b = 3
f(b)
1.b = 3,b在模块级绑定,即b是全局变量,把值存储在全局符号表
2.f1(b),调用函数f(b),实参b被引入函数f1的局部符号表
1.函数块内赋值b = a = int型对象3的地址值,存储在该函数的局部符号表中
3.a = 4,函数块内赋值,值(int型对象4的地址值)存储在该函数的局部符号表
1.此时a存储在局部符号表中的值由int型对象3的地址值变成了int型对象4的地址值,即变量a所指向的对象改变
4.print(a),引用变量a,在函数f1的局部符号表中找到a的值,根据该值访问int型对象4
-------------------------------------------------------------------------------------------------------------
def f1(a):
print(id([0])) #1568742546
a[0] = 4
print(id(a[0])) #2564578412
print(a)
b = [3]
f1(b)
1.b = [3],b在模块级绑定,即b是全局变量,把值存储在全局符号表
2.f(b),调用函数f(b),实参b被引入函数f1的局部符号表
1.函数块内赋值b = a = 列表对象[3]的地址值,存储在该函数的局部符号表中
3.print(id(a[0])),引用变量
1.首先在函数f1的局部符号表中找到列表对象a的地址值,根据该地址值访问列表对象[3]
2.然后根据该下标访问列表元素a[0]
1.列表中元素不是直接存储在列表中(即列表不是一块连续的内存空间),列表中有一个指向存储各元素对象地址值的数组的引用,通过该引用(数组的首地址)和下标找到(计算)数组中对应元素的地址,根据该地址访问元素对象实体
>>> num = [1, 2, 3]
>>> id(num)
2284487238152
>>> id(num[0])
1922872384
>>> id(num[1])
1922872416
>>> id(num[2])
1922872448
>>>
----------------
id(num[2]) - id(num[1]) = id(num[1]) - id(num[0]) = 32 --- 说明是顺序存储结构
4.a[0] = 4,修改元素值,实际上是改变了列表中所引用数组指定位置存储的地址值,即新创建的int型对象4的地址值
5.print(id(a[0])),与3中输出的地址值不同,也说明了4中的观点
6.print(a),引用变量,在函数f1局部符号表中找到变量a的值,根据该值访问列表对象[4]
-------------------------------------------------------------------------------------------------------------
def f1(a):
print(id(a)) #2284487238728
a = [4] --- 覆盖,变量a原来存储到局部符号表中的值(名称num1绑定的列表对象的的地址值)被新值(列表对象[4]的地址值)覆盖
print(id(a)) #2284487238152
print(a)
b = [3]
f1(b)
1.b = [3],b在模块级绑定,即b是全局变量,把值存储在全局符号表
2.f(b),调用函数f(b),实参b被引入函数f1的局部符号表
1.函数块内赋值b = a = 列表对象[3]的地址值,存储在该函数的局部符号表中
3.print(id(a)),引用变量,在函数f1局部符号表中找到a的值,根据该值访问队列表对象[3]
4.a = [4]函数内赋值,值(列表对象[4]的地址值)存储在该函数的局部符号表
1.此时存储在局部符号表中的a的值由列表对象[3]的地址值变成了列表对象[4]的地址值,即变量a的指向改变
5.print(id(a)),引用变量,在函数f1局部符号表中找到a的值,根据该值访问列表对象[4]
6.print(a),同5
=======================================================================================
二.当可变对象的元素是不可变对象(数字, 元组, 字符串, bytes等),在修改元素值时似乎这些不可变对象可以被修改 --- 事实并非如此,这里的改变实际上是改变了列表内部数组存储对应元素对象的位置上的地址值,即改变了指向的对象
num = ["123", "22", "3"]def f():
print(type(num[0])) #<class 'str'> --- 字符串
print(id(num[0])) #2314830389296
num[0] = "22" #--- 修改字符串
print(id(num[0])) #2314830389352
num[0][0] = "7" #TypeError: 'str' object does not support item assignment
f()
1.print(type(num[0]))说明列表元素对象为字符串类型
2.print(id(num[0])) #2314830389296
3.num[0] = "2" 改变列表元素的值,单从表面看似乎是对字符串进行修改,但是字符串不是不可变对象吗?
4.print(id(num[0])) #2314830389352,对比2可以发现实际上是改变了列表内部数组中对应位置上存储列表元素对象的地址值,由原来的字符串对象"123"的地址值,变成了"22"的地址值
1.Note: 对于已存在的不可变对象,python不会重新创建,即此时列表对象内部数组中保存第一个元素和第二个元素地址值的位置上的值相等,都指向字符串对象"22"
5.num[0][0] = "7"#TypeError: 'str' object does not support item assignment, 可以发现字符串对象确实是不可变对象
0 0
- 彻底理解python中函数内赋值操作和对象的可变性
- python 赋值变量和赋值对象的可变性
- python对象的引用特征和可变性
- Python中对象的理解:引用和赋值
- python--关于对象的可变性
- python不可变性和可变性的区别
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- JavaScript中原型对象的彻底理解
- 流程的Python 第八章:对象引用、可变性和垃圾回收
- python数据的可变性
- Python中常见的文件对象内建函数
- 对象可变性的管理和创建使用值对象,
- 什么是P问题、NP问题和NPC问题
- 【Spring】使用Spring发送邮件
- AngularJS路由 $state服务、路由事件、获取路由参数
- ZOJ2208-To and Fro
- TextView 加边框
- 彻底理解python中函数内赋值操作和对象的可变性
- 树形DP
- Android之用命令uninstall卸载apk和用 -i 过滤日志忽略大小写
- 《JavaScript》*****src路径属性
- Easybet88 Online Casino Malaysia VIP Chip Redemption(Easybet88, Easybet88 Online, Sportbook, VIP Chi
- 洛谷P3369 普通平衡树(Treap/Splay)
- 选择排序算法
- Reporting Service 2012 体系结构
- C#用DesignSurface实现一个简单的窗体设计器