Python是面向对象的编程语言,在Python程序中创建的变量、函数、类等一切均为对象。
对象有三要素,标识(身份或身份码)、类型和值。
如,赋值语句n=1,创建一个int类的实例对象,值为1,然后把对象1的引用赋给变量n。
在程序中每创建一个独立对象就会为对象分配一块内存,并为对象分配一个唯一的身份码,且身份码是不会改变的。
给变量赋值后,变量存储的是对象引用(object reference),通过引用可以查找到对象在内存中的位置,可以把引用理解为指向或链接。
赋值
n = 1 # 赋值语句可以理解为,在等号右侧创建值为1的int类的实例对象,然后把该对象的引用赋给标识符n
m = 1
print(id(n) == id(m)) # id函数返回对象的唯一身份码
# 变量n和变量m的身份码一样,说明两者指向了同一个对象
m = 2.1 # 标识符m重新赋值,改为存储另一个float类的实例对象的引用
t = (1, 2)
t1 = (1, 2)
t2 = t # t2和t指向同一个对象,变量t2仅为t所有存储的对象的别名
print(id(t), id(t1), id(t2)) # 变量t和变量t1存储的对象引用不同,虽然两个引用对应的 \
# 类型和值相同,但两个对象在内存中地址不同
"""
变量存储的是对象的引用,可以有多个变量指向同一个对象,即这些变量保存的是相同的对象引用。
当一个变量修改对象时,因为修改的是共有的对象,所以其他变量也跟着改变。
"""
ls = [1, 2]
ls1 = ls # 别名,两个变量指向同一个对象
print("变量ls1和变量ls的id相同:", id(ls1) == id(ls))
ls.append(3) # 两个变量同时被修改
print(ls, ls1)
dic = {"a": 1, "b":2}
dic1 = dic # 别名,两个变量指向同一个对象
print("变量dict1和变量dict的id相同:", id(dic) == id(dic1))
dic1["a"] = 100 # 两个变量同时被修改
print(dic, dic1)
set1 = {"a", "b"}
set2 = set1 # 别名,两个变量指向同一个对象
print("变量set1和变量set的id相同:", id(set1) == id(set2))
set2.add("c") # 两个变量同时被修改
print(set1, set2)
class Car:
def __init__(self, price):
self.price = price
def set_price(self, value):
self.price = value
car1 = Car(100)
car2 = car1 # 别名,两个变量指向同一个对象
print("变量car2和变量car1的id相同:", id(car2) == id(car1))
car1.set_price(60) # 两个变量同时被修改
print(car1.price, car2.price)
深拷贝和浅拷贝
复制列表有浅拷贝和深拷贝两种方式:
浅拷贝创建两个独立的列表,但两个列表的元素为同一个实例对象。
深拷贝创建两个独立的列表,并且两个列表中的元素为不同的实例对象,即两个列表完全分开,互不影响。
# 深拷贝和浅拷贝
import copy
ls1 = [[1, 1], [2, 2]]
ls2 = copy.deepcopy(ls1) # 深拷贝
ls3 = copy.copy(ls1) # 浅拷贝
ls4 = list(ls1) # 浅拷贝
print(id(ls1), id(ls2), id(ls3), id(ls4)) # 4个变量的对象引用各不相同,4个独立的列表
# 列表内增减元素互不影响
ls1.append('a')
ls2.append('b')
ls3.append('c')
ls4.append('d')
print(ls1, ls2, ls3, ls4, sep='; ')
# 修改列表元素
ls2[0][0] = 2
print(ls1, ls2, sep="; ") # 深拷贝,元素独立
ls3[0][0] = 3
print(ls1, ls3, sep="; ") # 浅拷贝,元素相同
ls4[0][0] = 4
print(ls1, ls4, sep="; ") # 浅拷贝,元素相同