看书还是能学到新东西的,好好的了解了一下Python的Dynamic Typing以及垃圾收集。收获蛮大。
Numeric Type:
这是最常用也是最简单的数据类型。值得注意的是 // 和 / 在python2 和 python3 中的区别。在python3中,/ 始终是浮点除。
1 2 3 4 5 6 7 8 9 10 11 12 | python2: >>> 1 // 2 0 >>> 1 / 2 0 python3: >>> 1 // 2 0 >>> 1 / 2 0.5 >>> |
python的各种进制数也很好用。关键输出要注意,比如输出16进制,前面会自动加上0x,这在有些情况下是不希望出现的。使用format就可以解决这个问题。数的操作都比较浅显易懂,Fraction等都已经涉及过。估计也难得用python来位操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 | i = 12345678998765431 b = 0b1010001 o = 0o7662314 h = 0xa231c ii = int("11010",10) ib = int("11010",2) io = int("11010",8) ih = int("11010",16) print(ii, bin(ib), oct(io), hex(ih) ) print("format: {0:o}, {1:x}, {2:b}".format(io, ih, ib)) print(ib.bit_length()) |
Dynamic Typing:
Python的优点之一是不需要声明变量类型。这是怎么做到的?Python的每个变量都可以认为是一个指针,更确切是”Reference”。然后变量引用对象。对象知道自己是什么对象。因为每个对象都有 type designator和reference counter,所以”Types Live with Objects, Not Variables”。类型根本不关变量的事。
这样做就需要垃圾管理机制。就是python的gc。每当引用变为0,就可以回收该对象的内存空间。但是这里有一个很著名也很普通的问题: cyclic references。比如
L = [1,2],L.append(L) ,就构成了一个循环引用。Python是怎么处理的我就不管了。
当Python要比较的时候,可以用 ==,代表的是值相等,也可以用is,代表的是引用是否相同。比如:
1 2 3 4 5 6 7 8 9 | #equality L = [1,2,3] M = L print( M == L) # True print( M is L) # True M = [1,2,3] print( M == L) # True print( M is L) # False |
因为这种机制,很多对象都是共享的(Shared References )。不可变类型不要紧,可变类型就有问题,一旦改变某个变量的引用,就会使其他变量也变化,就是所谓的in-place object changes。要灵活运用L[:]和copy.deepcopy()
refcount 和 weakref:
不深入看看Python的引用是无法完全理解这种机制的。还好Python提供了查看引用的方法。这里要注意对于一个数的引用是出乎意料的,这是因为Python的Cache机制。反正数是不可变的,多给引用完全没有问题。同样小字符串也是有cache的。然后这里sys.getrefcount,总是多1,查看文档,发现这是因为这个函数本身就临时引用了一次变量,想想蛮有道理。
1 2 3 4 | import sys L = [1,2] print(sys.getrefcount(12)) # May large print(sys.getrefcount(L)) # 2 |
为了避免cyclic references,python提供了 weak ref机制,主要原理是这次引用不增加对该对象引用的计数,就相当于没引用。好吧,我讲不清。看这里。然后代码也能说明一切。这个功能的主要作用是防止一些大对象不能及时回收。list,dict什么的不能直接支持,要包裹一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import weakref import gc class Dict(dict): pass print("week ref testing") origin = Dict({"a":1,"b":2,"c":3}) print(sys.getrefcount(origin)) r = origin print(sys.getrefcount(origin)) #3 wr = weakref.ref(origin) print(sys.getrefcount(origin)) #3 r = 1 #remove ref print(sys.getrefcount(origin)) #2 gc.collect() assert wr() is origin origin = 1 #remove ref print(sys.getrefcount(origin)) #any gc.collect() assert wr() is None |