python变量内存浅析

时间:2022-12-12 16:21:29

1. Python变量

   如果把单一值变量称为一维变量,把可以扩展元素的变量称为多维变量,则python的变量可以划分如下:

变量维度

Python变量

说明

一维

数字

int(有符号整型)

数字类型可以做转换

long(长整型[也可以代表八进制和十六进制])

float(浮点型)

complex(复数)

字符串

字符串有丰富的运算符和内嵌函数;

有格式化输出;

二维

列表

除了元祖外,列表和字典可以灵活的扩展元素

元组

字典

2. Python变量的赋值处理

   这里主要分析情况为,将原始变量赋值给新变量后,二者的变化关联情况,比如:原始变量为varold,新变量varnew = varold,之后varnew发生了变化,那么varold如何变化,二者的地址情况如何?这里给出测试用例:

   用例1

def whole_modify(value_old, value_new):
    #before
    obj_old = value_old
    obj_new = obj_old
    print(obj_old, id(obj_old))
    print(obj_new, id(obj_new))
    #after
    obj_new = value_new
    print(obj_old, id(obj_old))
    print(obj_new, id(obj_new))
print('value:')
whole_modify('aaa', 9)
print('list:')
whole_modify(['a', 2], [3, 'b'])
print('Dictionary:')
whole_modify({1:'a', 'b':2}, {3:'c'})

   测试结果:

value:

('aaa', 38126200)

('aaa', 38126200)

('aaa', 38126200)

(9, 4014992)

list:

(['a', 2], 43066072)

(['a', 2], 43066072)

(['a', 2], 43066072)

([3, 'b'], 41421080)

Dictionary:

({1: 'a', 'b': 2}, 39583440)

({1: 'a', 'b': 2}, 39583440)

({1: 'a', 'b': 2}, 39583440)

({3: 'c'}, 39599104)

   用例1whole_modify是对新变量的整体修改,即直接用=号将一个全新的数据整体赋值给新变量,从测试情况看,结论是:

   不论一维还是二维变量,通过=号整体赋值后,新变量会重新分配内存,值为新赋给的值;原变量保持不变。

   用例2

print("list:")
obj_old = ['a', 2]
obj_new = obj_old
print(obj_old, id(obj_old))
print(obj_new, id(obj_new))#after
obj_new[0] = 3
print(obj_old, id(obj_old))
print(obj_new, id(obj_new))

print("dictionary:")
obj_old = {1:'a', 'b':2}
obj_new = obj_old
print(obj_old, id(obj_old))
print(obj_new, id(obj_new))#after
obj_new['b'] = 'newvaluestr'
print(obj_old, id(obj_old))
print(obj_new, id(obj_new))

   测试结果:

list:

(['a', 2], 39932832)

(['a', 2], 39932832)

([3, 2], 39932832)

([3, 2], 39932832)

dictionary:

({1: 'a', 'b': 2}, 40107728)

({1: 'a', 'b': 2}, 40107728)

({1: 'a', 'b': 'newvaluestr'}, 40107728)

({1: 'a', 'b': 'newvaluestr'}, 40107728)

   用例2中,主要是对二维变量内部元素做修改(一维变量无需测试),从测试情况看,结论是:

   老二维变量被赋给新二维变量后,对二者任何一个的内部元素修改,二者的地址不会发生改变,但值会同步被修改。

3. 分析

   Python的变量赋值(包括传参,返回参数等场景),与c/c++区别很大,而且很难用一句话概括其用法。上面两个测试用例主要是从变量类型的角度来区分,具有很强代表性,可以引申到很多场景辅助理解。

   很多人将python的变量赋值当做引用看待,这应该是有问题的,比如上面用例1中,很显然就不是引用,因为新变量地址和值都变化了,而老变量完全保持不变。而c/c++引用的概念是,新老变量地址不变,值同步变化。

   用例2中对二维变量做局部修改,会发现新老变量的局部元素的地址和值都同步变化了(变量本身地址不变),这个和引用相同的地方是值同步变化了,不同的是变量地址也同步变化了。

   Python的这种处理,应该是基于内存效率的考虑,虽然python应用开发中不用考虑变量地址与内存回收,但如果对变量赋值的内存情况完全忽视,则很容易产生意外的结果。