python的对象引用

首先要理解python中的变量只是一个标注,不是真正的值。

对象标识,值和别名

先看看这个例子:

a = [1,2]
b = a
a.append(3)
b
Out[4]: [1, 2, 3]

a,b都是指向了同一个对象。

id(a)
Out[5]: 2101610153608
id(b)
Out[6]: 2101610153608

也就是说,赋值指的是对象的引用。

a,b指代了同一个对象

a is b

Out[8]: True

也表明了a,b是指代同一对象,再看看这个

c = [1,2,3]
a == c
Out[11]: True
a is c
Out[12]: False

b是a别名,c却不是a的别名,因为a和c绑定的不是同一个对象。具体的看官方文档

Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. The ‘is‘ operator compares the identity of two objects; the id() function returns an integer representing its identity.

现在我们就可以看看is和==的区别,is比较的是对象的标识,==比较两个对象的值(对象中保存的数据)。is比==快,因为is是不能重载的,而a==b是语法糖(这个和scala一样),等同于

a.__eq__(b)。

元组的相对不可变性

a = (1,2,[3,4])
b = (1,2,[3,4])
a == b
Out[15]: True
a[2].append(2)
a
Out[20]: (1, 2, [3, 4, 2])
id(a)
Out[21]: 2101633577464
a == b
Out[22]: False

那么你想要复制列表要怎么做呢?

a = [1,2]
b = list(a)
a == b
Out[25]: True
a is b
Out[26]: False

通过内置的数据类型的构造方法实现了浅复制。

但是

a = [1,[2,3]]
b = list(a)
a.append(4)
a
Out[35]: [1, [2, 3], 4]
b
Out[36]: [1, [2, 3]]
a[1].remove(2)
b
Out[38]: [1, [3]]

这个a,b虽然是不同的列表,但是内部的列表却是指向同一个对象,这也就是浅的含义。

深呢,就是副本不共享内部对象

a = [1,[2,3]]
b = copy.deepcopy(a)
a[1].remove(2)
b
Out[48]: [1, [2, 3]]

有一个问题就是循环引用的问题,对象会引用不该复制的外部资源或单例值,这时候就要自己实现__deepcopy__方法了

引用和函数参数

函数的传递模式呢,指的是函数的各个形式参数获得实参中各个引用的副本。函数内部的形参是实参的别名,也就是函数可以修改

作为参数传入的可变对象,但是无法修改它们的标识。

def f(a,b):
    a += b
    return a
x = 1
y = 2
f(x, y)
Out[52]: 3
x = [1,2]
y = [3]
f(x, y)
Out[55]: [1, 2, 3]
x
Out[56]: [1, 2, 3]

当x是可变的列表时,实际上经过一个函数,已经发生了改变。

原文发布于微信公众号 - 鸿的学习笔记(shujuxuexizhilu)

原文发表时间:2017-08-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小樱的经验随笔

C/C++对bool operator < (const p &a)const的认识,运算符重载详解(杂谈)

下面来进行这段代码的分析: struct node {  //定义一个结构体node(节点) int x; int y; int len;   //nod...

3366
来自专栏ccylovehs

JavaScript 深入之从原型到原型链

在这个例子中, Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person 。 很简单吧,接下来进入正题:

4324
来自专栏前端正义联盟

一道 js 闭包面试题的学习

最近看到一条有意思的闭包面试题,但是看到原文的解析,我自己觉得有点迷糊,所以自己重新做一下这条题目。

3474
来自专栏java一日一条

浅谈Java中的equals和==

为什么第3行和第4行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就会导致自己在以后编写代码时出现一些低级...

572
来自专栏静默虚空的博客

Java正则速成秘籍(二)之心法篇

导读 正则表达式是什么?有什么用? 正则表达式(Regular Expression)是一种文本规则,可以用来校验、查找、替换与规则匹配的文本。 又爱又恨的正...

19010
来自专栏xiaoxi666的专栏

【非原创】C++类成员函数的重载、覆盖和隐藏

B、重载是指派生类函数覆盖基类函数,函数相同,参数相同,基类函数必须有virtual关键字

742
来自专栏LanceToBigData

JavaSE(四)之接口、访问控制

上面我们学习了几个修饰符,在开发中经常会用的到,所以必须熟练的掌握。接下来我学习一下接口和访问控制。 一、接口 一系列方法的声明,是一些方法特征的集合,一个接口...

2347
来自专栏Java帮帮-微信公众号-技术文章全总结

String中的null,以及String s;等区别详解

1、判断一个引用类型数据是否null。 用==来判断。 2、释放内存,让一个非null的引用类型变量指向null。这样这个对象就不再被任何对象应用了。等待JVM...

3544
来自专栏微信公众号:Java团长

浅谈Java中的equals和==

  为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就会导致自己在以后编写代码时出现一些...

963
来自专栏数据结构与算法

05:输出亲朋字符串

05:输出亲朋字符串 总时间限制: 1000ms 内存限制: 65536kB描述 编写程序,求给定字符串s的亲朋字符串s1。  亲朋字符串s1定义如下:给定...

4156

扫码关注云+社区