2024.1.19 Python学习笔记6

本文介绍了Python中不可更改对象(如数字和字符串)与可更改对象(如列表)的区别,以及is运算符的工作原理。重点讲解了列表拷贝(浅拷贝和深拷贝)、元组的创建和解包,以及如何处理字符串的字符操作。
摘要由CSDN通过智能技术生成

is运算符、温习可更改与不可更改对象

阅读如下代码:

a=1
b=1
print(a is b)
#True

a='12345'
b='12345'
print(a is b)
#True

a=[1,2,3]
b=[1,2,3]
print(a is b)
#False

在学习笔记1中提到过可更改与不可更改对象的概念,上面代码中,1、'12345',分别是数字、字符串对象,都是不可更改对象,而[1,2,3]是列表对象,是可更改对象。

不可更改对象由于不可更改,后续操作本身就不能修改a、b指向的内容,因此在前面两个例子中,只需要分配一份内存空间存储1或'12345',然后a与b同时指向同一位置即可;而后面一个例子中的列表作为可更改对象,在后面的操作中,可能对a进行修改更新,此时要保证不能影响b的内容,因此虽然a与b创建时存储内容相同,但仍需要分配两个内存空间存储两个列表,使两个列表相互独立。

下面的代码也可以印证上面的解释:

a=1
b=1
print(id(a),id(b))
#140721224558384 140721224558384

a='12345'
b='12345'
print(id(a),id(b))
#2387846888176 2387846888176

a=[1,2,3]
b=[1,2,3]
print(id(a),id(b))
#2387847475712 2387853152896

可见,前两类对象,a与b的地址相同,而在列表对象时,标识符存在区别。从这里也可以看出,is语句实际判断的是对象的标识符是否相同。

有时需要类似于c语言,创建一个全0的二维数组,这种方法是错误的,原因也可以见上面所讲:

a=[[0]*3]*3
print(a)
#[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

a[0][1]=1
print(a)
#[[0, 1, 0], [0, 1, 0], [0, 1, 0]]

print(id(a[0]),id(a[1]))
#2040579330880 2040579330880

通过输出列表第0、1个元素标识符,可见,指向的都是同一个位置,即a中嵌套的三个列表实际都是同一个,因此,对每一行列表修改,都会影响其他两个列表。我们希望的列表结构应该是这样:

 实际创建的却是这样:

 正确创建应当是这样:

a=[]
for i in range(3):
    a.append([0 for j in range(3)])
#更精炼:a=[[0]*3 for i in range(3)]
print(a)
#[[0,0,0],[0,0,0],[0,0,0]]
a[0][1]=1
print(a)
#[[0,1,0],[0,0,0],[0,0,0]]

列表拷贝

列表拷贝不能直接用=运算符进行所谓理解的赋值,应当使用copy()方法或者列表切片实现,原理上面已有解释。

x=[1,2,3]
y=x
z=x.copy()  #使用copy()方法
w=x[:]      #使用切片
x[1]=1
print(x,y,z,w)  #y跟随x修改,z、w则未变化
#[1, 1, 3] [1, 1, 3] [1, 2, 3] [1, 2, 3]

上面的方法称为浅拷贝。但是在处理嵌套列表时,浅拷贝仍然会出现问题:

x=[[1,2,3],[4,5,6],[7,8,9]]
y=x
z=x.copy()  #使用copy()方法
w=x[:]      #使用切片
x[1][1]=1
print(x)
#[[1, 2, 3], [4, 1, 6], [7, 8, 9]]
print(y)
#[[1, 2, 3], [4, 1, 6], [7, 8, 9]]
print(z)
#[[1, 2, 3], [4, 1, 6], [7, 8, 9]]
print(w)
#[[1, 2, 3], [4, 1, 6], [7, 8, 9]]
print(id(x[0]),id(y[0]),id(z[0]),id(w[0]))
#1836198588928 1836198588928 1836198588928 1836198588928

可见,修改嵌套列表中子列表内容,复制的列表同样会受到影响。观察标识符可见,复制列表中相同位置子列表标识符完全相同,推导得出,浅复制只是将最外层列表创建,内部元素仍然是直接引用。此时需要借助于深拷贝才能处理嵌套列表。

import copy
x=[[1,2,3],[4,5,6],[7,8,9]]
y=copy.copy(x)  #浅拷贝
z=copy.deepcopy(x)  #深拷贝
x[1][1]=1
print(x)
#[[1, 2, 3], [4, 1, 6], [7, 8, 9]]
print(y)
#[[1, 2, 3], [4, 1, 6], [7, 8, 9]]
print(z)
#[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

其中的deepcopy()就是深拷贝函数,可见,深拷贝的列表z,并不会因x改变而改变。

顺带注意,这个代码中的y=copy.copy(x),与y=x.copy()不是同一copy。前一个是copy库中的copy函数,后一个则是列表中的copy方法。

python字符串与ord函数

需要注意python不同于c语言,将字符串作为迭代对象的循环中,取出的仍然为字符串而不是字符。如果想要像c语言那样对字符进行操作,需要借助于ord函数,如下所示:

a=[x*3 for x in '1234567']
code=[ord(x) for x in '1234567']
print(a)
#['111', '222', '333', '444', '555', '666', '777']
print(code)
#[49, 50, 51, 52, 53, 54, 55]

元组

元组声明创建时使用圆括号,但也可以不用。

a=(1,2,3)
b=4,5,6
print(a,b)  #(1, 2, 3) (4, 5, 6)

创建只有一个元素的元组,不是直接在那一个元素外面加个括号:

a=(123456)  #错误方法,只会生成整型数据
print(a,type(a))
#123456 <class 'int'>

b=(123456,) #正确方法
print(b,type(b))

当元组中存在N个元素时,可以将其直接赋值给N个变量,称其为元组解包。需要注意,解包时要求元组中元素数量与赋值的变量数量相同,否则会报错。实际这种行为也适用于任何的序列类型,例如列表、字符串。

a=(1,2,3)   
b,c,d=a #元组解包
print(b,c,d)    #1 2 3

元组内容并不是严格的不能修改,如果元组中的元素属于可修改对象,该元素之中的实际可以修改。

a=([1,2,3],[4,5,6])
a[0][0]=0   #a中元素是列表,列表内元素仍然可以修改
print(a)
#([0, 2, 3], [4, 5, 6])
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值