来源: ApacheCN『USF MSDS501 计算数据科学中文讲义』翻译项目原文:Data Aliasingpython
译者:飞龙git
协议:CC BY-NC-SA 4.0程序员
编程最棘手的事情之一是确切地肯定变量所指的数据。 请记住,咱们使用data
和salary
这样的名称来表示保存数据值的内存单元。 名称比物理内存地址更容易记住,但咱们可能被愚弄。 例如,显然两个变量x
和y
均可以具备相同的整数值 7:github
x = y = 7 print(x,y) # 7 7
可是,你知道他们都指的是同一个 7 对象吗? 换句话说,Python 中的变量始终是引用或指向数据的指针,所以变量在技术上并非持有值。 指针就像电话号码“指向”手机,但指针自己不是手机自己。apache
咱们可使用内置的id(x)
函数来发现这个间接的秘密层次,该函数返回由x
指向的物理内存地址。 为了证实这一点,让咱们问一下x
和y
指向的是什么:编程
x = y = 7 print(id(x)) print(id(y)) ''' 4468307488 4468307488 '''
哇! 他们是同样的。 该数字表示 Python 存储共享对象 7 的内存位置。数组
固然,做为程序员,咱们并不认为这些原子元素指的是同一个对象;请记住他们这样作。 咱们更有可能将它们视为相同数字的副本,由于lolviz
在视觉上显示:数据结构
from lolviz import * callviz(varnames=['x','y'])
让咱们验证字符串是否发生了一样的事情:svg
name = 'parrt' userid = name # userid now points at the same memory as name print(id(name)) print(id(userid)) ''' 4506178760 4506178760 '''
好的,很好,因此咱们实际上共享相同的内存地址来保存字符串'parrt'
,而且两个变量名都指向同一个共享空间。咱们在语言实现中称之为别名。函数
当咱们开始更改共享数据时,事情才会变得怪异。整数和字符串不会发生这种状况,由于它们是不可变的(没法更改)。让咱们看一个列表的两个相同副本:
you = [1,3,5] me = [1,3,5] print(id(you)) print(id(me)) callviz(varnames=['you','me']) ''' 4508962504 4508962440 '''
这些列表具备相同的值,但存在不一样的内存地址。他们不是别名;它们不是共享的。所以,更改一个不会改变另外一个:
you = [1,3,5] me = [1,3,5] print(you, me) you[0] = 99 print(you, me) ''' [1, 3, 5] [1, 3, 5] [99, 3, 5] [1, 3, 5] '''
另外一方面,让咱们看看若是咱们让you
和me
共享相同的列表副本(指向相同的内存位置)会发生什么:
you = [1,3,5] me = you print(id(you)) print(id(me)) print(you, me) callviz(varnames=['you','me']) ''' 4509139464 4509139464 [1, 3, 5] [1, 3, 5] '''
如今,更改一个彷佛改变另外一个,但实际上二者都恰好引用内存中的相同位置:
you[0] = 99 print(you, me) callviz(varnames=['you','me']) # [99, 3, 5] [99, 3, 5]
不要混淆“更改列表元素”和“更改指向列表的指针”:
you = [1,3,5] me = you callviz(varnames=['you','me'])
me = [9,7,5] # doesn't affect `you` at all print(you) print(me) callviz(varnames=['you','me']) ''' [1, 3, 5] [9, 7, 5] '''
当咱们将列表或其余数据结构传递给函数时,这种数据别名大量存在。 将Quantity
列表传递给其参数名为data
的函数,意味着这两个是别名。 咱们将在使用函数组织代码的“符号可见性”部分中,更详细地查看这个现象。
X = [[1,2],[3,4]] Y = X.copy() # shallow copy callviz(varnames=['X','Y'])
X[0][1] = 99 callviz(varnames=['X','Y']) print(Y) # [[1, 99], [3, 4]]