python基础 第7章 复杂数据类型-1-Python 变量的指针本质

Python 的复杂数据类型包括组合数据类型和自定义数据类型。

组合数据类型有:str(字符串)、tuple (元组)、list(列表)、dict(字典)、set(集合)。

组合数据类型的名称本身也是函数的名称,可以用于类型转换。

例如:

 L = list("abcd") #L 值为['a','b','c','d']

Python中的函数isinstance(x,y)用于判断x是不是y类型的数据。 此处y是类型的名称。

例如:

 a = "1233"
 print(isinstance(a,str))    #>>True
 print(isinstance("123",int))    #>>False
 b = [1,3]   #b 是一个列表
 print(isinstance(b,list))   #>>True

Python中的len函数用于求组合数据类型中元素的个数。

例如,求字符串长度,列表元素个数:

 print(len("12345"))     #>>5 求字符串长度
 print(len([1,2,3,4])    #>>4 求列表长度
 print(len((1,2,3)))     #>>3 求元组长度
 print(len({1,2,3}))     #>>3 求集合元素个数
 print(len({'tom':2,'jack':3})) #>>2 求字典元素个数

组合数据类型中的字符串和元组是不可以修改的。 列表、字典和集合可以修改。

自定义数据类型也叫“类” ,在本章最后一节讲述。

7.1 Python 变量的指针本质

Python 中所有的变量,都是指针。

所有可赋值的东西都是变量,因此都是指针。

列表的元素是可赋值的,因此列表的元素就是指针。

指针的本质是内存地址。

可以将指针理解为一个箭头,它指向内存单元中存放的数据。

变量是箭头,对变量进行赋值,就是将该箭头指向内存中的某处,而不是改写该箭头指向的地方的内容。

请注意:其他程序设计语言中的变量,未必是上述的情况。也有的教材称Python变量是“引用”,和这里说的指针含义相同。但在其他语言里,“引用”和“指针”未必是一个意思。

 a = 3
 b = 4

对变量赋值,就是让变量指向某处。上面两条赋值语句的效果,可以理解为图7.1.1。

a 是个指针,指向内存中某处存放的 3。b一样是指针,它指向 4。

用一个变量对另一个变量进行赋值,就是让两个变量指向相同的地方。因此,若再执行:a = b产生的效果如图 7.1.2 所示。

a指向了b指向的地方,所以a的值也变成4。我们说变量a的值是4,归根到底是在说:a 指向4。

Python 中有两个运算符,"is"和"==",含义有所不同,但有些类似。

a is b 为 True,说的是a和b指向同一个地方;而a==b为True,说的是a和b指向的地方的内容相同,但a和b未必指向同一个地方。

Python中有一个函数id(x),能求表达式x的id。id不能说是内存地址,但类似于内存地址。两个变量如果指向同一个地方,等价于它们的id相同。

例如:

 #prg0440.py
 a = [1,2,3,4]   #列表a指向了[1,2,3,4]
 b = [1,2,3,4]    #列表b也指向了[1,2,3,4]
 print(a is b)   #False a和b指向的不是同一个列表[1,2,3,4]
 print(a == b)   #True a和b内容相同
 c = a   #c = [1,2,3,4]
 print(a == c)   #True
 print(a is c)   #True
 a[2] = "ok" #列表a下标为2的元素修改为 ”ok" a = [1,2,"ok",4]
 print(c)
 print(b)
 print(id(a) == id(c))   #True a和c指向的是同一块内存地址
 print(id(a) == id(b))   #False a和b指向的不是同一块内存地址

上面程序执行完第5行时,效果如图7.1.3所示。

内存中有两份列表[1,2,3,4], a和b分别指向它们。因此a和b指向不同的地方,但是它们指向的地方存放的内容是一样的。故第3行输出True而第4行输出False。

第5行使得c与a指向同一份列表。因此第6、7行都输出True。

第8行修改了a[2],情况变为如图7.1.4所示。

因为c和a指向同一个地方,所以a的内容变了,c的内容自然也变。所以输出c,结果就是[1,2,'ok',4]。

常见错误:初学者经常会写出a=b=[]这样的语句,本意是形成a、b两个不同的空表。但实际上这么写的结果,a、b都指向同一张列表,往a里添加元素,就等于往b 里添加元素。

对于 int、float、complex、str、tuple 类型的变量 a 和 b,只需关注 a == b 是否成立,一般不需要关注a is b是否成立。因为这些数据本身都不会更改,不会产生a指向的内容变了,b 指向的内容也跟着变的情况。

对于list、 dict、set类型的变量a和b,a==b和a is b的结果都需要关注。因为这些数据本身会改变,有可能发生改变了a指向的内容, b指向的内容也会改变的情况。

本课程中说a和b相等,或a和b的值相等,意思是a==b成立。而a is b可能成立,也可能不成立,要看具体情况。

因为列表的元素可以被赋值,因此,列表的元素其实也是指针。

 a = [1,2,3,4]
 b = [1,2,3,4]

执行完上面这两条语句,准确的效果如图 7.1.5 所示。

a和b的每个元素,如a[0],b[1],都是指针。

a[0]和b[0]没有分别指向不同的两个1,是因为1 本身不可变,没有必要保有两份。若对a[0]进行赋值,那就是让a[0]指向别处,而不是将a[0]所指向的那个1改成别的内容。

所以,假如a[0]被赋成别的值, b[0]并不会受影响,它仍然指向1。

Python 函数的参数也是指针。

Python 函数的形参是实参的复制——即形参和实参指向同一个地方。

对形参赋值就是让形参指向别处,当然不会影响实参。

例如:

 def Swap(x,y):
     tmp = x
     x = y
     y = tmp
 a,b = 4,5
 Swap(a,b) #x = a,y = b
 print(a,b)  #>>4 5

进入Swap函数时,x等于a, y等于b。

Swap函数执行的过程中交换了x, y的值,但这并不会影响a和b。

在函数中的tmp=x刚执行完时,效果如图7.1.6所示。

函数Swap(x,y)执行完的效果,交换了x和y的内存指向:

此刻x, y分别是a和b的复制,即x和a同指向4, y和b同指向5。tmp=x使得tmp也指向4。

Swap函数执行完后,x和y的值交换了,本质上是说x和y交换了它们的指向,因此情况变成图 7.1.7 所示。

显然, a和b的指向不会发生任何变化,它们的值自然不变。

但是如果函数执行过程中,改变了形参所指向的地方的内容,则实参所指向的地方内容也会被改变。

例如:

 #prg0450.py
 def Swap(x,y):
     tmp = x[0]
     x[0] = y[0]   #请注意若x,y是列表,则x[0],y[0]都是指针
     y[0] = tmp
 a = [4,5]
 b = [6,7]
 Swap(a,b)     #进入函数后, x和a指向相同地方, y和b指向相同地方
 print(a,b)  

这个程序中, Swap(a,b)使得 a 和 b 的下标为 0 的元素发生了交换。

这是因为,x和 a指向同一张列表[4,5], y和b指向同一张列表[6,7]。因此x[0]就是a[0], y[0]就是b[0]。

进入Swap函数,执行完tmp=x[0]时,情况如图7.1.8所示。

Swap交换了x[0]和y[0],也就交换了a[0]和b[0]。因此该函数执行完时,情况如图7.1.9所示

由于a和x指向相同的地方,所以x[0]变了,a[0]自然也变。b和y的关系亦然。

函数的返回值也是指针。

假设函数中的返回语句是return x,如果x是变量,则返回值和x指向相同的地方;如果x是一个非变量的表达式,那么返回值指向这个表达式的计算后的值。

可赋值的东西都是指针,但是指针未必都可赋值。

例如函数的返回值,就是不可赋值的。比如f是个无参数的函数,f()的返回值就是指针。

a=f() 是用f的返回值对a进行赋值,使得a和f的返回值指向同一个地方。但f()=100这种写法是不可行的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值