python变量类似于引用式变量,因此可以理解为附加在对象上的标注
charles = {"name": 'charles', "age": 30}
lews = charles
print(charles==lews)
print(charles is lews)
元组的相对不可变性:
集合,列表,字典等python集合保存的式=是对象的引用,元组的不可变性指的是tuple数据结构的物理内容(及保存的引用)不可变,与引用的对象无关。
t1 = (1, 2, [3, 4])
t2 = (1, 2, [3, 4])
print(t1 == t2) # true
print(t1 is t2) # false
print(id(t1[-1]))
t1[-1].append(5)
print(t1)
print(id(t1[-1])) # 依然不可变 这才是元组不可变的本质
副本与源对象, 浅复制
复制列表等可变对象,有两种方法:
# method 1
a = [12, 23, [11, 22], (7, 8, 9)]
b = list(a) # a是源对象, b是副本
# method 2
b = a[:] # 复制
copy模块提供的copy()和deepcopy()能为任意对象做求浅复制和深复制
from copy import copy, deepcopy
class Bus:
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
self.passengers = list(passengers)
def drop(self, name):
self.passengers.remove(name)
def pick(self, name):
self.passengers.append(name)
def __repr__(self):
return "Passengers are: " + str(self.passengers)
if __name__=="__main__":
passenger = ["Lily", "Nosy", "Tom"]
bus1 = Bus(passenger)
bus2 = copy(bus1) # copy函数
bus3 = deepcopy(bus1) # deepcopy函数
print(bus1)
bus1.pick("liu")
print(bus1)
print(bus2)
print(bus3)
输出结果:
此外,可以通过实现特殊方法__copy__()和__deepcopy__()能够控制copy的行为。
参数传递
python唯一支持的参数传递模式是共享传参。共享传参指函数的各个形式参数获得实参中各个引用的副本,也就是说函数内部的实参是形参的别名。
可对上面的程序做一个小的修改
from copy import copy, deepcopy
class Bus:
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
# self.passengers = list(passengers) # 相当于创建实参的一个副本,所以形参变化,实参不变化
self.passengers = passengers # 形参是实参的别名,python中参数传递的方式
def drop(self, name):
self.passengers.remove(name)
def pick(self, name):
self.passengers.append(name)
def __repr__(self):
return "Passengers are: " + str(self.passengers)
if __name__=="__main__":
passenger = ["Lily", "Nosy", "Tom"]
bus1 = Bus(passenger)
bus2 = copy(bus1) # copy函数
bus3 = deepcopy(bus1) # deepcopy函数
print(bus1)
bus1.pick("liu")
print(bus1)
print(bus2)
print(bus3)
print(passenger) # pick方法对函数内部的形参做了修改
# 形参是实参的引用,所以说实参也会跟着变化
不同类型的对象的实参,传入函数中后,会受到不同的影响
1. 数组和元组没变
2. 列表变了
不适用可变类型作为函数的默认值
可选参数可以有默认值,这是python的一个特性,能保证API在进化的时候向后兼容, 但是,应该避免使用可变的对象作为参数的默认值。
例如对上面的代码作如下修改:
passenger = ["Lily", "Nosy", "Tom"]
bus1 = Bus(passenger)
bus1.pick("wang")
bus1.drop("Lily")
print(bus1)
bus2 = Bus() # 使用了默认的参数值
print(bus2)
bus2.pick("zhang")
bus3 = Bus() # 使用默认参数,但此时默认的参数(可变对象)已经被修改
print(bus3) # 修改了之后。bus3中有值了
输出结果:
在修改bus2的时候,实际上修改了传递给构造方法的那个列表,所以bus3中出现了一个“幽灵” 乘客。
正确的做法是:Bus类应该自己维护passenger列表,应该做到在构造方法中将实参的副本传递给实参。这样就不会影响初始化的时候传递的参数了。
del和垃圾回收:
del语句删除名称,而不是对象,del命令可能会导致对象被当作垃圾回收,但是仅当删除的变量保存的是对象的最后一个引用的时候。
cpython中,垃圾回收采用的算法是引用计数,实际上,每个对象都会统计有多少个引用指向自己,当引用计数归零时,对象立即会被销毁。
原文链接: https://www.cnblogs.com/ncepubye/p/12724046.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/396647
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!