《流畅的Python》读书笔记–第8章

1.课上老师经常讲的变量看为盒子,其实变量应该看做标识。
2.python中,is比较的是标识即内存地址;==比较的是值。这就涉及到了效率问题,is经常用来比较变量和单例值,即最常使用的是用is检查变量绑定的值是不是None,a is None / a is not None。is的运算速度比==快,因为is不能重载;==是python中的语法糖,等同于__eq__(),继承自object的__eq__。在相等性测试中可能会涉及到大量的工作,例如比较大型集合和嵌套层级较深的结构。
3.元组与python集合(列表,字典,集…)一样,保存的是对象的引用,而str、bytes、array.array等单一序列是扁平的,而是在连续的内存中保存的数据本身。
4.元组的相对不可变性。元组的物理内容(即保存的引用)不可变,也就是说元组的标识不可变。但是元组中的可变对象仍不受限制,举例来说元组中的列表可变,就此来说这个元组中的值是可变的。
5.推荐www.pythontutor.com网站,可视化代码执行过程。
6.使用浅复制时,操作容易但是得到的结果可能不是你想要的。使用浅复制,副本是引用对象的标识,对本体的可变对象做了操作时,会影响到副本;但是对副本(对象)不可变对象操作时,会改变所引用的对象,创建一个新的元组给副本(对象),这时副本的(对象)的id变了,而对象(副本)的id不变。
对于不可变元组修改的例子:
t1 = (1, 2)
t2 = t1
print(id(t1), t1)
print(id(t2), t2)

t1 += (3, 4)   # 此处可以改成t2 += (3, 4)
print(id(t1), t1)
print(id(t2), t2)
7.深复制的意思是,副本不共享内部对象的引用。copy模块提供了deepcopy()和copy()函数。copy()函数执行的是浅复制,对象和副本的改变会相互影响;deepcopy()函数执行的是深复制,对象和副本互不影响。
copy和deepcopy的例子(流畅的python):

import copy


class Bus:
    def __init__(self, passengers=None):
        if passengers == None:
            self.passengers = []
        else:
            self.passengers = passengers

    def pick(self, name):
        self.passengers.append(name)

    def drop(self, name):
        self.passengers.remove(name)


bus1 = Bus(['zhang', 'lee', 'wang'])
bus2 = copy.copy(bus1)
bus3 = copy.deepcopy(bus1)

print()
print(id(bus1), id(bus1.passengers), bus1.passengers)
print(id(bus2), id(bus2.passengers), bus2.passengers)
print(id(bus3), id(bus3.passengers), bus3.passengers)

bus2.drop('zhang')
print()
print(id(bus1), id(bus1.passengers), bus1.passengers)
print(id(bus2), id(bus2.passengers), bus2.passengers)
print(id(bus3), id(bus3.passengers), bus3.passengers)


bus1.pick('liu')
print()
print(id(bus1), id(bus1.passengers), bus1.passengers)
print(id(bus2), id(bus2.passengers), bus2.passengers)
print(id(bus3), id(bus3.passengers), bus3.passengers)
8.但是深复制涉及到循环引用的情况。deepcopy处理循环引用的时候,会记住复制过的对象,因此处理起来不会陷入循环中。
deepcopy的例子:
import copy

a = [10, 20]
b = [a, 30]
a.append(b)
print(a)

c = copy.deepcopy(a)
print(c)
9.python唯一支持的传参方式:共享传参(call by sharing)。共享传参指的是函数形参获得的是实参中各个引用的副本,即实参的别名。可引起的问题是,能够修改传入的可变参数。
10.没有指定参数的实例(缺省参数的实例)会共享一个可变对象(当可变对象是形参时)。当不确定是不是需要修改形参时,建议创建副本。如何创建副本,看以下实例:

class Bus:
    def __init__(self, passengers=None):
        if passengers==None:
            self.passengers=[]
        else:
            self.passengers=passengers
以上判断了是否形参为缺省,若是则创建副本,
11.del和垃圾回收。del函数不删除对象,只删除对象的引用,当对象的引用为0是,对象会被当作垃圾回收(此时对象不可获取)。(https://emptysqua.re/blog/pypy-garbage-collection-and-a-deadlock/ 对__del__方法的恰当用法和不当用法做了讨论)
12.弱引用。弱引用不会增加引用数量,不影响垃圾回收。弱引用的应用,当出现 循环引用或者一组对象相互引用,而没有被其他对象直接引用并且不可访问,则这些对象就能永久的活下来,无法被回收。当有程序持续不断地产生这样的对象时,就会发生内存泄漏。弱引用 用来解决以上问题。
weakref类是低层接口,供高级用途使用,应尽量使用WeakKeyDictionary、WeakValueDictionary、WeakSet、finalize,不建议自己动手创建和处理weakref.ref实例。
实例:

import sys
import weakref

class Student:
    def __init__(self, name=None):
        if name==None:
            self.name="None"
        else:
            self.name=name

S = Student('zhang')
print(sys.getrefcount(S))

wr = weakref.ref(S)
print(sys.getrefcount(S))

print(S)
print(wr)

S1=wr()
print(sys.getrefcount(S))

S1=None
print(sys.getrefcount(S))
S=None
print(sys.getrefcount(S))

print(wr)
13.弱引用的局限。不是每个python对象都可以作为弱引用的目标。例如list和dict的实例不能作为所指对象。但是其子类可以,例如:

class MyList(list):
    def __init__():
        pass

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注