美文网首页
第六章 与对象的深入交往 总结

第六章 与对象的深入交往 总结

作者: 大饼与我 | 来源:发表于2020-01-13 20:37 被阅读0次

    一 一切皆对象

    1 运算符


    1.1.1运算符中的特殊方法的操作

    如果用dir(list)调查list的属性,可以看到一个属性是_add_()这个特方法,它定义了“+”运算符对于list对象的意义。两个list的对象相加时,会进行合并列表的操作。

    >>>print([1,2,3]+[5,6,9]) #得到 [1,2,3,5,6,9]

    运算符,比如+、-、>、<、and、or的能都是通过特殊方法实现的。

    >>>" abc "+ "xyz" #连接字符串,获得“abcxyz”,实际上执行了”abc._add_("xyz")的操作

    两个对象能否进行加法运算的关键就要看相应的对象是否有_add_()方法。

    别的例子:

    >>>(1.8)._mul_(2.0) #1.8*2.0

    >>>True._or_(False) #True or False


    1.2.1 运算符中特殊方法的拓展操作

    运算相关的特殊方法还可以改变执行运算的方法。

    比如>>>[1,2,3]-[3,4] 是无法进行减法操作的,因为列表没有定义“-”的运算符,我们可以创建一个列表的子类,通过增加_sub_()的方法来增加减法操作的定义。


    2 元素引用

    2.1 _gtitem_()方法

    下面时我们常见的表元素引用方法:

    li=[1,2,3,4,5,6]

    print(li[3]) #打印4

    上述python发现并理解[]符号,然后调用_getitem_()方法

    li=[1,2,3,4,5,6]

    print(li._getitem_(3)) #打印4


    3 内置函数的实现

    与运算符类似,许多内置函数也都是调用对象的特殊方法。

    >>>len([1,2,3]) #返回表中元素的综合

    实际上是:

    >>>[1,2,3]._len_()

    别的例子:

    >>>(-1).__abs__()

    >>>(2.3).__int__()

    二 属性管理

    1 属性管理

    1.1属性管理的背后

    为了深入理解属性覆盖,我们有必要理解Python的__dict__属性。当我们调用调用对象的属性时,这个属性可能来自对象属性、类属性、还有可能从祖先类那里继承来的。一个类或对象拥有的属性,会记录再__dict__中。这个__dict__时一个词典,键为属性名,对应的值为某个属性。python在寻找对象的属性时,会按照继承关系依次寻找__dict__

    一个例子:

    子类的属性不父类的同名属性有优先权,这正是属性覆盖的关键。

    值得注意的是:上面都是调用属性的操作,如果进行赋值,那么Python就不会分层深入查找了。


    2 特性

    同一个对象的不同属性之间可能存在依赖关系。 当某个属性被修改时,我们希望以来与该属性的其他属性也同时变化。python提供了多种即时生成属性的方法,其中一种称为特性(property)。即特殊的属性。

    特殊属性通过内置函数property()来建立。property()最多可以加载四个参数,前三个参数为函数,分别用于设置获取、修改和删除特性时,Python应该执行的操作。最后一个参数为特性的文档,可以为一个字符串起到说明作用。

    一个例子:


    3 .__getattr__()方法

    除了内置函数property外,我们还可以用__getattr__(slef,name)来查询即时生成的属性。

    每个特性都需要有自己的处理函数,而__getattr__()可以将所有的及时生成属性都放在同一个函数集中处理。需要特别注意的是,__getattr__()只能用于查询不在__dict__系统中的属性。

    三 我是风儿,我是沙

    1 动态类型(Dynamic Typing)

    几个概念:

    对象名是只想这一对象的引用(reference),对象是村粗在内存中的实体

    ①通过内置函数id(),我们能看到引用指向的是哪个对象:

    返回的编号相同

    ②除了直接打印的id外,我们还可以用is运算来判断两个引用是否指向同个对象。

    2 变与不可变对象

    ①一个对象可以有多个引用,看下面这个例子:#不可变对象的例子

    对象没变,只是引用变了,从效果上看就是各个引用各自独立,互不影响。这就是不可变对象

    ②列表自身能发生改变的对象,称为可变对象(Mutable Object)

    一个例子:


    3 从动态类型看函数的参数传递

    函数的参数传递本质上传递的是引用。

    不可变对象 可变对象


    四 内存管理


    1 引用管理

    对象内存管理是基于对引用的管理。在Python中,引用与对象分离。一个对象可以有多个引用,而每个对象都存有指向该对象的引用总数,即引用计数(Reference Count)

    我们可以i使用标准库中sys包中的getrefcount(),来查看某个对象的引用计数,需要注意的是,当使用某个引用作为参数,传递给getrefcount()时,参数实际上时创建了一个临时引用。因此,getrefcount()所得到的结果会比期望多1.


    2 对象引用对象

    对象引用对象的例子

    注意:当一个对象a被另一个对象b引用,a的引用计数将增加1:

    容器对象的引用可能会构成很复杂的拓扑结构:

    x=[1,2,3]

    y=[x,dict(key1=x)]

    z=[y,(x,y)]

    import objgraph

    两个对象可能相互引用,从而构成引用环(Reference Cycle)

    a=[ ]

    b=[a]

    a.append(b)

    即便是单个对象,只需要自己引用自己,也能构成引用环:

    a=[ ]

    a.append(a)

    print(getrefcount(a))

    3 垃圾回收(Garbage Collection)

    3.1基础回收

    原理上,当Python的某个对象的引用计数降为0了,即没有任何引用指向对象时,该对象就成为要被回收的垃圾了。

    如:

    a=[1,2,3]

    del a #删除a之后,没有任何引用指向[1,2,3],表[1,2,3]将被清除

    Python指挥在特定的条件下,自动启动垃圾回收。当Python运行时,会记录其中分配对象那个和取消分配对象的起初,当两者的差值高于某个阈值时,垃圾回收才会启动。

    我们可以通过gc模块的get_threshold()方法,查看该阈值。

    import gc

    print(gc.get_threshold())

    返回(700,10,10)后面的两个10时与分代回收相关的阈值。700是立即回收启动的阈值。


    3.2分代回收

    python同时还采用了分代回收的策略。

    python将所有对象分为0、1、2三代。所有新建对象都是0代对象。当某一带对象经历过垃圾回收,依然存活,那么它将被归入下一代对象。垃圾回收启动时,一定会扫描所有0代对象。如果0代对象经历过一定次数的垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了一定次数的垃圾回收后,就启动对0、1、2代的扫描,即对所有对象进行扫描。

    get_threshold()返回的(700,10,10)返回的两个10,意思是,每10次0代垃圾回收,会配合1次1的乐基回收,而每10次1代回收,才会有1次2代的垃圾回收。

    可以采用set_threshold()来调整次数

    import gc

    gc.set_threshold(700,10,5)

    4 孤立的引用环

    这些引用环可能构成无法使用,但引用计数不为0的一些对象,会给垃圾回收机制带来很大的困难。

    为了回收这样的引用环,Python会赋值每个对象的引用计数,可以记作gc_ref。假设,每个对象i,该计数为gc_ref_i.Python会遍历所有的对象i。对于每个对象i所引用的对象j,将相应的gc_ref_j减1.

    在结束遍历后,gc_ref不为0的对象和这邪恶对象引用的对象,以及继续更下游引用的对象,需要被保留,而其他对象则被垃圾回收。

    相关文章

      网友评论

          本文标题:第六章 与对象的深入交往 总结

          本文链接:https://www.haomeiwen.com/subject/hqtwactx.html