《从python开始学编程》第六章总结

6.1一切皆对象

运算符

当我们建立两个列表对象相加时,实际上是调用了__add()__特殊方法,而这些功能相同的运算符使程序更加简洁。
乘法对应的特殊方法是__mul__(),、or逻辑或运算符对应的方法是__or__(),。
改变在这些与运算符相关的对应特殊方法可以改变运算的方式。例如:列表中并没有关于列表对象的减法操作,我们可以通过修改特殊方法来定义,如下


class SuperList(list):
  def __sub__(self,b):
    a = self[:]              #继承了list,self可以通过[:]的引用来表示整个列表
    b = b[:]
    while len(b) > 0:
      element_b = b.pop()    #去掉b列表中的元素并将其返回。
      if element_b in a:
        a.remove(element_b)
    return a
print(SuperList([1,2,3])) - SuperList(([3,4]))    #输出[1,2]

元素引用

我们常用的元素引用,其实也是调用特殊方法,如:
li[3]其实是调用了__getitem__()方法

内置函数的实现

许多内置函数的实现也是调用了对象的特殊方法,如:
len()函数是调用了__len__()方法
而abs()方法是调用了__abs()__方法,int()调用了__int__()方法

6.2属性管理

属性覆盖的背后

python中的__dict__属性,会记录一个类或对象拥有的属性。__dict__也可以从祖先类继承。例如:一个“鸟”类,下面有一个子类“鸡”类,我们创建了这个“鸡”类的一个对象summer,那么这个对象就继承了“鸡”类和“鸟”类的属性,还拥有自身的属性。
当我们在 调用属性的时候,会从_\dict__中记录的对象向下遍历,调用优先遇到的属性。其遍历顺序summer/chicken/Bird/object(属性是分层管理的)。


【注】而当我们赋值的时候,python不会分层查找,直接在summer的__dict__的记录中寻找,若没有对象属性,则创建一个新的属性并赋值;使用self引用对象也要准守相同规则。

特性

特性:即时生成属性的方法,通过内置函数property()来创建。
【注:】property()有四个参数,分别用于设置获取、修改、删除时的特性,最后一个参数是特性的文档,起说明作用


class num(object):
  def __init__(self,value):
    self.value = value
  def get_neg(self):
    return -self.value
  def set_neg(self, value):
    self.value = -value
  def del_neg(self):
    print("vlaue also deleted")
    del self.value
neg = property(get_neg, set_neg, del_neg, "I'm negative")

x = num(1.1)
print(x.neg)          #输出1.1
x.neg = -22
print(x.value)        #输出22
print(num.neg__doc__) #输出"I'm negative"
del x.neg

___getattr__()方法

上面我们接受了即时生成的属性方法,那么___getattr__()方法则是来查询即时生成的属性。
我们调用一个属性时,如果__dict__无法找到该属性,则会调用___getattr__()来即时生成该属性。
     【注:】该方法只能用于查询不在__dict__系统中的属性,若是在则会报错。
__setattr__(self,name,value)用来修改任意属性;__delattr__(self,name)用来删除任意属性;__getattribute__()用来查询任意属性。

6.3我是风儿,我是沙

动态类型

python中的变量不需要声明类型,可以重新赋任何值。
因为对象实际上是存在在内存中的实体,有自己的内存地址,而对象名只是指向某一内存地址从而来引用该对象,当我们将对象名重新赋值时,只是将它指向其他地址,因此可以重新赋任何值。


a = 3
print(id(a))    #输出的是3的地址
a = "at"
print(id(a))    #输出的是“at”的地址

我们也可以通过is来判断两个引用是否指向同一个地址:


a = 3
b = 3
print(a is b)    #输出True

可变与不可变对象

a = 5
print(id(5))
 b = a
print(id(a))       #输出5的地址
print(id(b))       #输出5的地址
a = a + 2
print(id(a))      #输出7的地址
print(id(7))       #输出7的地址
print(id(b))       #输出5的地址

通过上面的例子我们发现改变一个引用,并不影响其他引用。因为它的改变并没有改变对象本身。


list2 = [1,2,3]
list1 = list2
list1[0] = 10
print(list2)      #输出[10,2,3]

【注:】这里的改变并不是改变list1的指向,而是直接对列表对象进行操作,所以会导致其他引用也改变。
对于这种自身会发生改变的对象,称为可变对象。不能改变自身的对象,赋值时只改变引用的指向,这种对象称为不可变对象
【注:】整数、浮点数、字符串和元组都是不可变对象

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

函数的传递本质上传递的是引用,如:


def f(x):
  print(id(x))
  x = 100
  print(id(x))
a = 1
print(id(a))
f(a)
print(id(a))

【注:】如果a是不可变对象则x的赋值不影响a,若a是可变对象,则函数内部的赋值操作会影响a的值。

6.4内存管理

引用管理

引用计数:一个对象可以有多个引用,而每个对象中都存有指向该对象的引用总数。
我们可以使用sys包中的getrefcount()来查看某个对象的引用。


from sys import getrefcount
a = [1,2,3]
print(getrefcount(a))    #返回2
b = a
print(getrefcount(b))    #返回3

【注:】我们在使用某个引用作为参数传递给getrefcount()时,实际上创建了一个临时性的引用,所以结果会比实际引用多1。

对象引用对象

列表和字典这些可变对象它们其实都是数据容器对象,本身可以包含多个对象;但是容器对象中包含的并不是元素对象本身而是指向各个元素对象的引用。所以我们可以通过对象来引用对象。


class from_obj(object):
  def_init_(self, to_obj):
    self.to_obj = ob_obj
b = [1,2,3]
a = from_obj(b)
print(id(a.to_obj))
print(id(b))

【注:】容器中的引用会构成很复杂的拓扑结构,我们可以使用objgraph包来绘制其引用关系。
对象间相互引用会构成所谓的引用环
我们也可以通过del关键字来删除某个引用。

垃圾回收

当python中某个对象的引用计数为0时,该对象就会被垃圾回收。
python只在特定条件下自动启动垃圾回收,当python运行时,会记录分配对象和取消分配对象的次数,当两者差值高于某个阙值时,垃圾回收才会启动。
我们可以通过gc模块的get_threshold()方法来查看该阙值。
python中还采用了分代回收的策略,刚建立的对象为0代,经历过垃圾回收还存活的则归入下一代,共有三代,分别为0,1,2三代。0代经历过一定次数的垃圾回收后就会启动对1代的扫描清理。


import gc
print(gc.get_threshold()) 

若返回(700, 10, 10),700指垃圾回收启动的阙值,第一个10指0代经历十次垃圾回收则启动对1代的扫描处理,第二个十指1代经历了十次垃圾回收后启动对2代的垃圾回收。

孤立的引用环

a = []
b = a
a.append(b)
del a
del b

上面的代码a,b对象彼此互相引用构成一个引用环,在删除a,b后由于引用环的存在使得对象引用计数没有降为一,所以不会被垃圾回收。
为此,python会复制每个对象的引用计数,可以记为gc_ref,假设每个对象i,计数为gc_ref_i。
Python会遍历所有对象i对对象j的引用,将相应的gc_ref_j减一,在结束遍历后gc_ref不为0的对象以及这些对象的引用对象则保留,其他则回收。
python采用了一种相对简单的垃圾回收机制,即引用计数

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容