大道至简,知行合一。

Python高级编程和异步I/O并发编程笔记 6 对象引用、可变性和垃圾回收

python的变量到底是什么?

python和Java中的变量本质不一样,Java在声明一个变量时需要指明变量的类型,Java虚拟机会在内存中根据不同的类型申请不同大小的内存空间,python的变量实质是一个指针,逻辑上可以理解为“先创建对象,然后指针指向对象”

==和is的区别

==是比较“值”,is是比较“址”。

a= [1, 2, 3, 4]
b =[1, 2, 3, 4]
print(id(a), id(b))
print(a==b)
print(a is b)
a= 1
b= 1
print(a is b)       #此处就两个一样了,都为True,原理是因为python内部有intern机制,会对一定范围内的小整数建立全局对象,会将后面创建的变量直接指向该对象,这种python内部的优化机制,对于一些小段字符串如“abc”也适用。

del语句和垃圾回收

python中的垃圾回收算法是采用“引用计数”。原理是如下例,当有一个变量指向某个对象,如“a =1”,此时引用计数器会在1上“加1”,当“del a”时计数器会在1上“减1”。对比C++中的del语句会直接删除回收对象,python解释器会在引用计数减为0时将对象回收。当然,在cpython 2.0中垃圾回收算法不再是简单的记数机制,而是引入了“分代”机制。另外,我们可以在对象中实现“__del__”魔法函数,当解释器回收对象时执行我们定义的逻辑。

a = object()
b = a
del a
print(b)    #虽然a被删除了,但是其对象未被回收,b仍然保持引用有效
print(a)    #a被删除了,会抛出异常

一个经典的参数错误

def add(a, b):
    a += b
    return a
#第一种情况
a = 1
b = 2
c = add(a, b)
print(a, b, c)    #1, 2, 3
#第二种情况
a = [1, 2]
b = [3, 4]
c = add(a, b)
print(a, b, c)    #[1, 2, 3, 4], [3, 4], [1, 2, 3, 4]
#第三种情况
a = (1, 2)
b = (3, 4)
c = add(a, b)
print(a, b, c)    #(1, 2), (3, 4), (1, 2, 3, 4)
#列表传递进去参数出现这种问题的原因是,列表引用传入后“+=”就地加,导致被修改了。
#-----------------------------------------------#
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("com1", ["bobby1", "bobby2"])
com1.add("bobby3")
com1.remove("bobby1")
print (com1.staffs)

com2 = Company("com2")
com2.add("bobby")
print(com2.staffs)

com3 = Company("com3")
com3.add("bobby5")
print (com2.staffs)      #此处就会出现问题,com2和com3的staffs会是同一个对象
print (com3.staffs)
print(com2.staffs is com3.staffs)    #True
#出现上述问题的原因是com2和com3都使用默认的列表初始化,而list本身是可变对象,所以com2和com3就共用了一个对象,即默认的list,该对象可以通过“Company.__init__.__defaults__”来访问到。综上,开发时尽量不要使用list作为默认值,当传递list或dict到函数中时,我们需要注意这个值可能被修改。

赞(0)
未经允许不得转载:北凉柿子 » Python高级编程和异步I/O并发编程笔记 6 对象引用、可变性和垃圾回收
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址