Python 是一门面向对象的语言, 在Python一切皆对象。

每一个对象都有由以下三个属性组成:

------------------------------------------------------------------------------------------------------------

Identity(身份):

  它是每一个对象的身份唯一标识, 可通过 id(obj) 函数查询.

  对应于到现实生活, 可以理解成我们个人的身份证编号, 它可以唯一标识在 "地球" 这个范围内的每个人  

Type(类型):

  它是每个对象的 "操作"标识, 可通过type(obj) 函数查询

  不同的类型, 往往意味着具有不同得方法

  对应于现实生活, 可以理解成我们每个人不同的职业, 例如警察, 消防员, 医生, 律师, 医生..

  这些不同的身份职业, 会拥有对应的不同技能(方法), 例如警察能抓小偷, 医生能治病   

Value (值):

  它是每个对象具有的"数据", 不同类型的对象值的方式各异

在python中, 只要对象存在, 那么(id, type, value)就不会消失.

对于面向对象, 同样重要的一个概念便是引用:

------------------------------------------------------------------------------------------------------------


什么是引用? 这是许多人的困惑

为了解答这个问题, 让我们以简单的代码例子进行引入

In [1]: a = 10

In [2]: b = 10

In [3]: id(a) == id(b)
Out[3]: True

  

这里我们发现当 a 与 b的值相同的时候, id(a) 和 id(b)是完全相同的

在上面我们说过, id是对象的唯一标识, id相同意味着a和b指向的是同一个的对象

通过上面的图我们可以发现, 与C语言不同开辟内存空间来存储变量不同,

Python并没有为每一个变量开辟一个内存空间,  而是通过一种 "指向"的方式来使

变量 和 int对象(数字10)之间产生关联.

a 和 b 仅仅是一个符号链接到对象上

In [6]: a = 10 

In [7]: b = 10 

In [8]: id(a) == id(b)
Out[8]: True In [9]: a = 100 In [10]: id(a) == id(b)
Out[10]: False

这里我们发现, 我们对 a 进行重新赋值后

id(a) 不等于 id(b)了, 这表明 a 和 b 此时指向的并非是同一个对象

这个现象表明, a 作为一个符号链接是无法 改变 int对象(10)的值的

a = 100

该代码所做的, 是重新创建一个新整形对象, 赋值为100

将a链接到该对象中

In [12]: a = 100

In [13]: id_old = id(a)

In [14]: a = 'alpha'

In [15]: id_new = id(b)

In [16]: id_old == id_new
Out[16]: False

该例子中, 首先将 a "指向" 整形对象100

接着 将a 指向 字符串'alpha'  

这里着重需要说明的是, 由于 a "指向" 的改变, 导致了 整型对象100的消失

即对象毁灭, 这是python垃圾回收的问题, 不在次讨论.

至此Python的引用也浮现出来了, 所谓的引用也就是上面示例中的"指向",

python一切皆对象的特性, 使得我们的基本的赋值操作, 也需要先创建对应对象

然后, 利用符号链接 "指向" 该对象

关于引用的总结

------------------------------------------------------------------------------------------------------------

创建的符号链接, 能够指向对象

a = 10

b = 10

c = 10

赋值操作, 对于同一个整型对象, 不同的符号链接(a, b, c), 引用相同的对象(整型对象10)

a = 10

b = 10

a = 100

赋值操作, 对于符号链接引用不同整型对象

首先创建对象(整型对象100), 接着更改引用(a 指向 100)

可变对象 和 不可变对象  (mutable/immutable)

------------------------------------------------------------------------------------------------------------

Python中有多种不同的数据类型, 依据是否可变, 分类如下:

可变对象: list, dict

不可变对象: int,string,float,tuple

相信大家都会有这个疑问, "变"究竟是如何衡量的?

我们依然以以下几个简单的示例进行说明

In [1]: a = 10

In [2]: b = 10

In [3]: id(a) == id(b)
Out[3]: True

同样是上面的代码, 这里 a 和 b 指向相同的引用对象

说明了 python并没有为新的 链接符号 提供新的对象, 这就对象唯一

对象是不变的, 无论有多少个链接符号 连接到它身上, 都不会再创建多个相同得对象

In [4]: list_a = [10, 20]

In [5]: list_b = [10, 20]

In [6]: id(list_a) == id(list_b)
Out[6]: False

对于 list 可变对象, 这里 list_a, list_b 指向得都是 列表对象 , 这个对象都是 只有两个元素 10, 20

但是 list_a 和 list_b 两个符号链接的 id 却是不相等的 , 说明 list_a 和 list_b 引用的是两个不同的对象, 对象不唯一

每创建一个符号链接, 就会产生一个新的对象与之关联

综上所述, 可以得知, 所谓的 "变"

是对象个数得描述

不变是指对于拥有相同值的对象,  多个符号链接, 对应同一个对象 (多对1)

变是指对于用有相同值的对象, 多个符号链接, 对应多个不同的对象 (1对1)

拷贝和深度拷贝 (copy/deepcopy)

------------------------------------------------------------------------------------------------------------

对于拷贝的概念, 这早已渗透到给位的生活中了

拷贝是复制的代名词, 亦即产生一份副本

对于Python来说, 拷贝就是产生多一个一模一样的对象

对于不可变对象拷贝

In [11]: a = 10

In [12]: b = a 

In [13]: a = 100

In [14]: b
Out[14]: 10

不可变对象, 我们直接进行 等号(=) 的复制操作就可以了

对于可变对象拷贝

In [15]: list_a = [10, 20]

In [16]: list_b = list_a[:]

In [17]: id(list_a) == id(list_b)
Out[17]: False

这里必须要注意需要使用  list_b = list_b 而不是 list_b = list_a

如果使用 list_b = list_b 效果如下图所示

当我们尝试修改, list_a[0] = 'alpha' 的时候, list_b[0] = 'alpha'

这是由于 list_a 与 list_b 共享引用

造成两个符号链接(list_a, list_b), 对应同一个列表对象

对于拷贝的总结

---------------------------------------------

不可变对象拷贝:

等号(=)

可变对象(list)拷贝: 

方法1 : list_b = list_a[:]

方法2 : list_b = list_a.copy()

方法3 : import copy

       list_b = copy.copy(list_a)

---------------------------------------------

深度拷贝

深度拷贝是基于嵌套可变可变对象而言的

In [27]: import copy

In [28]: a = [[10, 20, 30], [100, 200], 111]

In [29]: b = copy.deepcopy(a)

In [30]: id(a) == id(b)
Out[30]: False

  

对于深度复制, 由于列表中有嵌套

如果仅仅通过上面可变对象的复制方法(ie. list_b = copy.copy(list_a)), 尽管也能创造出不同id的对象

但是它们的列表引用却会引用到相同的对象, 导致在改变列表的时候, 原本拷贝的列表也遭到改变

只有通过深度复制 才能真正产生一个独立拷贝

** 总结

--------------------------------------------------------

Python 一切皆对象

对象有三个属性: 身份, 类型, 值

引用是一种"指向" python的赋值操作是将 符号链接指向对象

可变不可变对象, 在于对象与符号链接的关系是一对一还是多对一

不可变对象拷贝: 等号即可

可变对象拷贝: 切片[:], copy(), copy.copy()

深度拷贝是对于嵌套可变对象的: copy.deepcopy()

深度拷贝使用了不恰当拷贝方法, 会导致改变对象导致拷贝对象也被改变

参考网站:

http://www.pythontutor.com/visualize.html#mode=edit

Python [拷贝copy / 深度拷贝deepcopy] | 可视化理解的更多相关文章

  1. C++ 默认拷贝构造函数 深度拷贝和浅拷贝

    C++类默认拷贝构造函数的弊端 C++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数.它们的特殊之处在于: (1) 当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且 ...

  2. 【python】copy浅拷贝和deepcopy深拷贝

    Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deep ...

  3. Python浅拷贝copy()与深拷贝deepcopy()区别

    其实呢,浅拷贝copy()与深拷贝deepcopy()之间的区分必须要涉及到python对于数据的存储方式. 首先直接上结论: —–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的 ...

  4. 浅表拷贝vs深度拷贝

    浅表复制,只是创建所有的值类型,所有的引用类型还是会指向被复制的对象的引用. 故,当被复制的对象的引用类型发生改变的同事,复制的对象相应的 引用类型的值也是会发生改变的. 所以事件字段也是一个引用类型 ...

  5. Python 直接赋值、浅拷贝和深度拷贝全解析

    直接赋值:其实就是对象的引用(别名,其实就是一个人今天叫张三 明天叫张狗子的意思).这个人比较自由单身狗嘛  可以恋爱可以分手  就是一个小屌丝. 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的 ...

  6. Python 直接赋值、浅拷贝和深度拷贝解析

    直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象 ...

  7. 图解Python的直接赋值与浅拷贝和深度拷贝三者区别

    直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象 ...

  8. Python直接赋值、浅拷贝和深度拷贝解析

    直接赋值:其实就是对象的引用(别名). 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象 ...

  9. Python 直接赋值、浅拷贝和深度拷贝区别

    Python 直接赋值.浅拷贝和深度拷贝区别 转自https://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-de ...

随机推荐

  1. java利用SuffixFileFilter统计目录下特定后缀名文件的数目

    /** * 文件处理类 * @author zhangcd * @date 2017年1月3日 */ public class FileUtil { /** * 得到所有后缀的数目 * * @para ...

  2. TCP、UDP的区别

    TCP(传输控制协议): 1)提供IP环境下的数据可靠传输(一台计算机发出的字节流会无差错的发往网络上的其他计算机,而且计算机A接收数据包的时候,也会向计算机B回发数据包,这也会产生部分通信量),有效 ...

  3. 二叉搜索树详解(Java实现)

    1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...

  4. python入门:while循环里面True和False的作用,真和假

    #!/usr/bin/env python # -*- coding:utf-8 -*- #while循环里面True和False的作用,真和假 """ n1等于真(Tr ...

  5. 【nginx】 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream

    2013/10/22 20:05:49 [error] 12691#0: *6 FastCGI sent in stderr: "Primary script unknown" w ...

  6. pycharm-install scipy

    懒得装双系统,所以在win7下用pycharm,python2.7 虽然机子本身是64位,但是安装包的时候,我居然需要下载32位的??迷:) 这次装的是scipy.在pycharm里添加不了,根据网上 ...

  7. leetcode-9-basic-binary search

    278. First Bad Version You are a product manager and currently leading a team to develop a new produ ...

  8. #ifndef、#def、#endif说明

    你所遇到的这几个宏是为了进行条件编译.一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一 部分内容指定编译的条件,这就是“条件编译”.有时,希望 ...

  9. 匈牙利算法 - Luogu 1963 变换序列

    P1963 变换序列 题目描述 对于N个整数0,1,-,N-1,一个变换序列T可以将i变成Ti,其中:Ti∈{0,1,-,N-1}且 {Ti}={0,1,-,N-1}. x,y∈{0,1,-,N-1} ...

  10. 缓存淘汰算法之LFU

    1. LFU类 1.1. LFU 1.1.1. 原理 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频 ...