python引用和对象详解

@[马克飞象]

python中变量名和对象是分离的

例子 1:

a = 1

这是一个简单的赋值语句,整数 1 为一个对象,a 是一个引用,利用赋值语句,引用a指向了对象1.

例子 2:

>>> a = 1
>>> id(a)
24834392
>>> a = 'banana'
>>> id(a)
139990659655312

第一个语句中, 2是储存在内存中的一个整数对象,通过赋值 引用a 指向了 对象 1

第二个语句中,内存中建立了一个字符串对象‘banana’,通过赋值 将 引用a 指向了 ‘banana’,同时,对象1不在有引用指向它,它会被python的内存处理机制给当我垃圾回收,释放内存。

例子 3:

>>> a = 3
>>> b = 3
>>> id(a)
10289448
>>> id(b)
10289448

在这里可以看到 这俩个引用 指向了同一个 对象,这是为什么呢? 这个跟python的内存机制有关系,因为对于语言来说,频繁的进行对象的销毁和建立,特别浪费性能。所以在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。

例子 4:

>>> a = 4
>>> b = a
>>> id(a)
36151568
>>> id(b)
36151568
>>> a = a+2
>>> id(a)
36151520
>>> id(b)
36151568

可以看到 a 的引用改变了,但是 b 的引用未发生改变;a,b指向不同的对象; 第3句对 a 进行了重新赋值,让它指向了新的 对象6;即使是多个引用指向同一个对象,如果一个引用值发生变化,那么实际上是让这个引用指向一个新的引用,并不影响其他的引用的指向。从效果上看,就是各个引用各自独立,互不影响。

例子 5:

>>> L1 = [1,2,3]
>>> L2 = L1
>>> id(L1)
139643051219496
>>> id(L2)
139643051219496 >>> L1[0] = 10
>>> id(L1)
139643051219496
>>> id(L2)
139643051219496
>>> L2
[10, 2, 3]

 同样的跟第四个例子那样,修改了其中一个对象的值,但是可以发现 结果 并不与 第四个栗子那样, 在本次实验中,L1 和 L2 的引用没有发生任何变化,但是 列表对象[1,2,3] 的值 变成了 [10,2,3](列表对象改变了)

 

在该情况下,我们不再对L1这一引用赋值,而是对L1所指向的表的元素赋值。结果是,L2也同时发生变化。

原因何在呢?因为L1,L2的指向没有发生变化,依然指向那个表。表实际上是包含了多个引用的对象(每个引用是一个元素,比如L1[0],L1[1]..., 每个引用指向一个对象,比如1,2,3), 。而L1[0] = 10这一赋值操作,并不是改变L1的指向,而是对L1[0], 也就是表对象的一部份(一个元素),进行操作,所以所有指向该对象的引用都受到影响。

(与之形成对比的是,我们之前的赋值操作都没有对对象自身发生作用,只是改变引用指向。)

列表可以通过引用其元素,改变对象自身(in-place change)。这种对象类型,称为可变数据对象(mutable object),词典也是这样的数据类型。

而像之前的数字和字符串,不能改变对象本身,只能改变引用的指向,称为不可变数据对象(immutable object)。

我们之前学的元组(tuple),尽管可以调用引用元素,但不可以赋值,因此不能改变对象自身,所以也算是immutable object.

例子 6:

l = [1,2,3]
for item in l:
item = 8
# 这里只是让item指向l[i]所指向的对象,item = 8,则item指向新的对象8,不改变l[i]
print(l) # [1,2,3]
for i in range(len(l)):
l[i] = 8
# 这里令l[i]指向新的对象 8
print(l) # [8,8,8]

例子 7:

l1 = []
a = 0
for i in range(1,5):
a = i
l1.append(a) # 添加的是a指向的对象
print(l1) # [1, 2, 3, 4] l2 = []
b = [1,2,3]
for i in range(1,5):
b[1] = i
l2.append(b) # 添加的是b指向的对象,它包括列表元素的引用,列表本身没有改变,只是列表项[1]指向的对象变了
print(l2) # [[1, 4, 3], [1, 4, 3], [1, 4, 3], [1, 4, 3]]
# 不是预料的 [[1, 1, 3], [1, 2, 3], [1, 3, 3], [1, 4, 3]]

可以参考例子5。所以,每次列表实际上都是添加同一个对象。

l2 = []
b = [1,2,3]
for i in range(1,5):
b[1] = i
l2.append(copy.copy(b))
# l2.append(copy.deepcopy(b)) 和copy.copy()结果一样
print(l2) # [[1, 1, 3], [1, 2, 3], [1, 3, 3], [1, 4, 3]]

copy.copy() 浅拷贝。只拷贝父对象,不会拷贝对象的内部的子对象。

那么,copy.copy()和copy.deepcopy()有什么区别呢?

l2 = []
b = [1,[4,5],3]
for i in range(1,5):
b[1][0] = i
l2.append(copy.copy(b)) # [[1, [4, 5], 3], [1, [4, 5], 3], [1, [4, 5], 3], [1, [4, 5], 3]]
# l2.append(copy.deepcopy(b)) # [[1, [1, 5], 3], [1, [2, 5], 3], [1, [3, 5], 3], [1, [4, 5], 3]]
print(l2)

copy.deepcopy() 深拷贝 拷贝对象及其子对象

例子 8:

函数的参数传递探究

def testPara(aList):
aList[0] = 8
print("inside function",aList) # [8, 2, 3] if __name__ == '__main__':
l1 = [1,2,3]
testPara(l1)
print(l1) # [8, 2, 3]
def testPara(aList):
aList = [1,2]
print("inside function",aList) # [1,2] aList重新指向一个新的对象 if __name__ == '__main__':
l1 = [1,2,3]
testPara(l1)
print(l1) # [1, 2, 3]

这里要想直接把l1在函数内改变,可以在函数return l1

def test(l:list):
l.pop(0) if __name__ == '__main__':
l = [1,2,3]
test(l)
print(l) # [2,3]

python引用和对象详解的更多相关文章

  1. Java中对象、对象引用、堆、栈、值传递以及引用传递的详解

    Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...

  2. Python对Excel操作详解

      Python对Excel操作详解 文档摘要: 本文档主要介绍如何通过python对office excel进行读写操作,使用了xlrd.xlwt和xlutils模块.另外还演示了如何通过Tcl   ...

  3. Python初学者常见错误详解

    Python初学者常见错误详解 0.忘记写冒号 在 if.elif.else.for.while.class.def 语句后面忘记添加 “:”   if spam == 42 print('Hello ...

  4. python基础之函数详解

    Python基础之函数详解 目录 Python基础之函数详解 一.函数的定义 二.函数的调用 三.函数返回值 四.函数的参数 4.1 位置参数 4.2 关键字参数 实参:位置实参和关键字参数的混合使用 ...

  5. python之sys模块详解

    python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...

  6. Window 对象详解 转自 http://blog.csdn.net/jcx5083761/article/details/41243697

    详解HTML中的window对象和document对象 标签: HTMLwindowdocument 2014-11-18 11:03 5884人阅读 评论(0) 收藏 举报 分类: HTML& ...

  7. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  8. mvc-servlet---ServletConfig与ServletContext对象详解(转载)

    ServletConfig与ServletContext对象详解 一.ServletConfig对象    在Servlet的配置文件中,可以使用一个或多个<init-param>标签为s ...

  9. django中request对象详解(转载)

    django中的request对象详解 Request 我们知道当URLconf文件匹配到用户输入的路径后,会调用对应的view函数,并将  HttpRequest对象  作为第一个参数传入该函数. ...

随机推荐

  1. json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值

    一.json相关概念 json,全称为javascript object notation,是一种轻量级的数据交互格式.采用完全独立于语言的文本格式,是一种理想的数据交换格式. 同时,json是jav ...

  2. axios + mock.js模拟数据实现前后端分离开发的实例代码

    首先就是必须安装axios和mock.js npm install axios npm install mockjs 1. 然后在文档src中新建一个mock.js文件,如图 2. 在main.js中 ...

  3. iOS.Animations.by.Tutorials.v2.0汉化

    翻译自:iOS.Animations.by.Tutorials.v2.0 前五章将向你介绍动画API-UIKit框架.这个API是专门设计来帮助你轻松轻而易举的为视图控件赋予生命,同时避免了核心动画的 ...

  4. Redis Cluster的搭建与部署,实现redis的分布式方案

    前言 上篇Redis Sentinel安装与部署,实现redis的高可用实现了redis的高可用,针对的主要是master宕机的情况,我们发现所有节点的数据都是一样的,那么一旦数据量过大,redi也会 ...

  5. java.lang.ArrayIndexOutOfBoundsException

    1.错误描述 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at com.you.m ...

  6. Web站点错误提示页面和默认访问页面设置

    1.asp.net 定制简单的错误处理页面 通常web应用程序在发布后,为了给用户一个友好界面和使用体验,都会在错误发生时跳转至一个自定义的错误页面,而不是asp.net向用户暴露出来的详细的异常列表 ...

  7. 芝麻HTTP:Scrapy-Splash的安装

    Scrapy-Splash是一个Scrapy中支持JavaScript渲染的工具,本节来介绍它的安装方式. Scrapy-Splash的安装分为两部分.一个是Splash服务的安装,具体是通过Dock ...

  8. C#的动态链接库和XML配置

    今天对昨天的实例进行了改进和提高,将堆排序和冒泡排序封装在一个动态链接库中,提供函数调用和事件委托.此外加入XML进行配置,在XML中存入相关配置信息,提供一个单独的XmlClass对其进行操作,加深 ...

  9. Ball HDU - 4811

    Jenny likes balls. He has some balls and he wants to arrange them in a row on the table. Each of tho ...

  10. jxl导入/导出excel(网上的案例)

    jxl导入/导出excel 1.jxl导入/导出excel案例,黏贴即可运行 package junit.test; import java.io.File; import java.io.IOExc ...