一. python变量到底是什么
python和Java的变量本质不一样,Java是定义好一个类型,然后申请一个空间(大小和类型有关),相当于一个盒子只能放固定类型,python变量的实质是一个指针(大小都相同),指向int,string等等,相当于一个便利贴(先生成对象,然后贴便利贴),可以贴在很多东西上。
a=[1,2] b=a b.append(3) #a和b贴在同一个对象上面 print(a) print(a is b) print(id(a),id(b))
二. ==和is的区别
is是判断是否是同一个对象,而==是判断值是否相等
a=[1,2,3] b=[1,2,3] print(a is b) print(id(a),id(b)) #为什么能判断是相等的,也是魔法函数(list中的__eq__) print(a==b)
对于小整数(python内部的intern机制),将一定范围的小整数(大概是-5~256),会建立全局唯一的变量,下次再遇到时直接指向之前的,小段的字符串,Python都有机制
#对于小整数(python内部的intern机制),将一定范围的小整数(大概是-5~256),会建立全局唯一的变量,下次再遇到时直接指向之前的,小段的字符串,Python都有机制 a=1 b=1 print(a is b) print(id(a),id(b))
类本身也是一个对象,而且全局只有唯一的:
#类本身也是一个对象,而且全局只有唯一的 class Person: pass p1=Person() print(type(p1) is Person)
三. del语句和垃圾回收(参考:Python垃圾回收机制)
1.python中垃圾回收算法采用引用计数(cpython2.0之后就不仅仅是)
#这里比如1的计数为1 a=1 #这时1的计数会加1,相当于1上面有两个引用它 b=a #这里没有回收1,只是将1的引用计数减一,当引用计数为0时就将这个对象回收 del a print(b)
2.标记清除:
标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。
对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。
3.分代回收:
分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象
4.可以自己写在类中写垃圾回收的逻辑(__del__魔法函数):
class A: def __del__(self): pass
四. 一个经典的错误
1.原因:列表(可变对象),+=是直接修改a2,而不是创建一个新的list,因此a2也变化了
def add(a, b): a += b return a if __name__=='__main__': a1=1 b1=2 c1=add(a1,b1) print(c1) print(a1,b1) #列表(可变对象),+=是直接修改a2,而不是创建一个新的list,因此a2也变化了 a2=[1,2] b2=[3,4] c2=add(a2,b2) print(c2) print(a2,b2) #元组是不可变对象 a3=(1,2) b3=(3,4) c3=add(a3,b3) print(c3) print(a3,b3)
2.原因:类中传递的列表是一个可变对象,com2和com3都没有传递list,因此使用的是默认的list,其实是共用的一个对象(且可变)
class Company: def __init__(self,name,staffs=[]): self.name=name self.staffs=staffs def add(self,staff_name): self.staffs.append(staff_name) def remove(self,staff_name): self.staffs.remove(staff_name) com1=Company('SWPU',['LYQ1','LYQ2']) com1.add('NEW3') com1.remove('LYQ2') #这里没有问题 print(com1.staffs) com2=Company('SWPU2') com2.add('LYQ_com2') print(com2.staffs) #默认值 print(Company.__init__.__defaults__) com3=Company('SWPU3') com3.add('LYQ_com3') print(com2.staffs) print(com3.staffs) #com2.staffs和com3.staffs是同一个对象 print(com2.staffs is com3.staffs) #默认值 print(Company.__init__.__defaults__)