6.1 一切皆对象
1.运算符
运算符,比如+、-、>、<、and、or等
>>>print([1,2,3] + [5,6,9]) # 得到[1, 2, 3, 5, 6, 9]
>>>"abc" + "xyz" # 连接字符串,获得"abcxyz"
>>>(1.8).__mul__(2.0) # 1.8*2.0
>>>True.__or__(False) # True or False
>>>[1,2,3] - [3,4]
我们可以创建一个列表的子类,通过增加__sub__()方法,来添加减法操作的 定义,例如:
__sub__()定义了“-”的操作:从第一个表中去掉第二个表中出现的元素。于是, 我们创建的两个SuperList对象,就可以执行减法操作了。即使__sub__()方法已 经在父类中定义过,但在子类中重新定义后,子类中的方法会覆盖父类的同名方 法。即运算符将被重新定义。
2.元素引用
表元素引用方式:
li = [1, 2, 3, 4, 5, 6]
print(li[3]) # 打印4
li = [1, 2, 3, 4, 5, 6]
li.__setitem__(3, 0)
print(li) # 返回[1, 2, 3, 0, 5, 6]
example_dict = {"a":1, "b":2}
example_dict.__delitem__("a")
print(example_dict) # 返回{"b":2}
3.内置函数的实现
len([1,2,3]) # 返回表中元素的总数
实际上做的是:
[1,2,3].__len__()
6.2 属性管理
1.属性覆盖的背后
通过前后的对比,我们可以很直观的看出__dict__的作用。
2 特性
3 __getattr__()方法
除内置函数property外,我们还可以用__getattr__(self, name)来查询即 时生成的属性。当我们调用对象的一个属性时,如果通过__dict__机制无法找到该 属性,那么Python就会调用对象的__getattr__()方法,来即时生成该属性,比 如:
6.3 我是风儿,我是沙
1.动态类型
2 可变与不可变对象
6.4 内存管理
2 对象引用对象
objgraph包来绘制其引用关系,比如:
两个对象可能相互引用,从而构成所谓的引用环(Reference Cycle)。
3 垃圾回收
当Python的某个对象的引用计数降为0,即没有任何引用指向该对象 时,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用, 对象的引用计数变为1。如果引用被删除,对象的引用计数为0,那么该对象就可以 被垃圾回收。比如下面的表:
a = [1, 2, 3]
del a
del a后,已经没有任何引用指向之前建立的[1, 2, 3]这个表了,即用户不可 能通过任何方式接触或者动用这个对象。这个对象如果继续待在内存里,就成为不 健康的脂肪。当垃圾回收启动时,Python扫描到这个引用计数为0的对象,就会将 它所占据的内存清空。
Python只会在特定条件下,自动启动垃圾回收。 当Python运行时,会记录其中分配对象(Object Allocation)和取消分配对象 (Object Deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会 启动。 我们可以通过gc模块的get_threshold()方法,查看该阈值:
import gc
print(gc.get_threshold())
返回(700, 10, 10),后面的两个10是与分代回收相关的阈值,也就是说,每10次0代垃圾回收,会配合1次1代的垃圾回收;而每10次1代的垃圾回 收,才会有1次2代的垃圾回收。 同样可以用set_threshold()来调整次数,比如对2代对象进行更频繁的扫描。
import gc
gc.set_threshold(700, 10, 5)
4 孤立的引用环
引用环的存在会给上面的垃圾回收机制带来很大的困难。这些引用环可能构成 无法使用,但引用计数不为0的一些对象:
a = []
b = [a]
a.append(b)
del a
del b
创建了两个表对象,并引用对方,构成一个引用环。删除了a、b引 用之后,这两个对象不可能再从程序中调用,因而就没有什么用处了。但是由于引 用环的存在,这两个对象的引用计数都没有降到0,所以不会被垃圾回收。
网友评论