Python中深淺拷貝 垃圾回收與 super繼承(六)
1 python拷貝
深拷貝,淺拷貝 與引用三者的區別
import copy
a = [1, 2, 3, 4, [‘a‘, ‘b‘]] #原始對象
b = a #賦值,傳對象的引用
c = copy.copy(a) #對象拷貝,淺拷貝
d = copy.deepcopy(a) #對象拷貝,深拷貝
a.append(5) #修改對象a
a[4].append(‘c‘) #修改對象a中的[‘a‘, ‘b‘]數組對象
print(‘a = ‘, a)
print( ‘b = ‘, b)
print( ‘c = ‘, c)
print(‘d = ‘, d)
輸出結果:
a = [1 , 2, 3, 4, [‘a‘, ‘b‘, ‘c‘], 5] #a執行兩次值追加操作
b = [1, 2, 3, 4, [‘a‘, ‘b‘, ‘c‘], 5] #賦值是對象的引用,b指向仍然是a,因此與a內容保持一致
c = [1, 2, 3, 4, [‘a‘, ‘b‘, ‘c‘]] #對象的淺拷貝外部list重新生成新的空間,但是嵌套數組的內存地址不變
d = [1, 2, 3, 4, [‘a‘, ‘b‘]] #深拷貝是所有的數組都新生成一個內存空間,與原來的脫離關系
2 python的垃圾回收機制
Python GC主要使用引用計數(reference counting)來跟蹤和回收垃圾。在引用計數的基礎上,通過“標記-清除”(mark and sweep)解決容器對象可能產生的循環引用問題,通過“分代回收”(generation collection)以空間換時間的方法提高垃圾回收效率。
1 引用計數
? PyObject是每個對象必有的內容,其中ob_refcnt
就是做為引用計數。當一個對象有新的引用時,它的ob_refcnt
就會增加,當引用它的對象被刪除,它的ob_refcnt
就會減少.引用計數為0時,該對象生命就結束了。
優點:
- 簡單
- 實時性
缺點:
- 維護引用計數消耗資源
- 循環引用
2 標記-清除機制
基本思路是先按需分配,等到沒有空閑內存的時候從寄存器和程序棧上的引用出發,遍歷以對象為節點、以引用為邊構成的圖,把所有可以訪問到的對象打上標記,然後清掃一遍內存空間,把所有沒標記的對象釋放。
3 分代技術
分代回收的整體思想是:將系統中的所有內存塊根據其存活時間劃分為不同的集合,每個集合就成為一個“代”,垃圾收集頻率隨著“代”的存活時間的增大而減小,存活時間通常利用經過幾次垃圾回收來度量。
Python默認定義了三代對象集合,索引數越大,對象存活時間越長。
舉例:
當某些內存塊M經過了3次垃圾收集的清洗之後還存活時,我們就將內存塊M劃到一個集合A中去,而新分配的內存都劃分到集合B中去。當垃圾收集開始工作時,大多數情況都只對集合B進行垃圾回收,而對集合A進行垃圾回收要隔相當長一段時間後才進行,這就使得垃圾收集機制需要處理的內存少了,效率自然就提高了。在這個過程中,集合B中的某些內存塊由於存活時間長而會被轉移到集合A中,當然,集合A中實際上也存在一些垃圾,這些垃圾的回收會因為這種分代的機制而被延遲。
3 python中 is與 == var與let
is比較的是兩者的內存地址 ==基本比較的是兩者的數值
is判定
判定值相等,內存地址也相等
a = 10
b = 10
a is b
Ture 常用的1-256計算機共用一個內存地址
a = 9999999
b = 9999999
a is b
False 數值較大的數類似長整型,計算機會生成新的內存地址
var與let
var 定義的變量可以重新被定義
let 定義的變量不能重新被定義
4 Python中 read readline readlines
read() 每次讀取整個文件,它通常用於將文件內容放到一個字符串變量中
readline 讀取下一行,使用生成器方法,返回字符串的對象
readlines 讀取整個文件到一個叠代器以供我們遍歷
#read
f = open("a.txt")
lines = f.read()
print(lines)
print(type(lines))
f.close()
#輸出
# hello
# python!
<type ‘str‘> #字符串類型
#readline
f = open("a.txt")
line = f.readline()
print(type(line))
while line:
print line,
line = f.readline()
f.close()
#輸出
#<type ‘str‘>
<type ‘str‘> #字符串類型
# hello
# python!
#readlines
f = open("a.txt")
lines = f.readlines()
print(type(lines))
for line in lines:
print(line)
f.close()
#輸出
<type ‘list‘>
# hello
# python!
5 python2 與 python3 的區別
contents | python3 說明 |
---|---|
print函數 | python3 打印帶括號 |
整除 | / 可以得到浮點數 |
Unicode | Unicode (utf-8) 字符串 |
xrange模塊 | 統一使用range,並新增__contains__ |
Raising exceptions/Handling exceptions | raise 與 as 關鍵字 |
next()函數 | 只保留next() , .next() 拋出屬性異常 |
for循環 | for 循環變量不會再導致命名空間泄漏 |
比較不可排序類型 | python不支持不同類型的比較 |
輸入input | 只允許input,取消了raw_input |
6 Python必須學會的super
(1) super() 繼承方法
在類的繼承中,如果重定義某個方法,該方法會覆蓋父類的同名方法,但有時,我們希望能同時實現父類的功能,這時,我們就需要調用父類的方法了,可通過使用 super
來實現
class Animal(object): #Animal為父類
def __init__(self, name):
self.name = name
def greet(self):
print ‘Hello, I am %s.‘ % self.name
class Dog(Animal): #Dog為子類
def greet(self): #Dog重定義了greet方法並繼承了父類的方法
super(Dog, self).greet() # Python3 可使用 super().greet()
print ‘WangWang...‘
>>> dog = Dog(‘dog‘) #實例化
>>> dog.greet() #調用greet方法
Hello, I am dog.
WangWang..
(2) super初始化
super
的一個最常見用法可以說是在子類中調用父類的初始化方法
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class A(Base):
def __init__(self, a, b, c):
super(A, self).__init__(a, b) # 初始化子類繼承父類super(子類名,self).__init__(父類參數)
self.c = c
Python3 可使用 super().__init__(a, b)
,這樣子類繼承父類的屬性的同時,有保持了自身獨有的屬性.
(3) 深入super
super其實與父類沒有實質的關聯
class Base(object):
def __init__(self):
print "enter Base"
print "leave Base"
class A(Base): #繼承base
def __init__(self):
print "enter A"
super(A, self).__init__()
print "leave A"
class B(Base): #繼承base
def __init__(self):
print "enter B"
super(B, self).__init__()
print "leave B"
class C(A, B): #多重繼承自A,B
def __init__(self):
print "enter C"
super(C, self).__init__() #super第一個參數可以是繼承鏈中任意類名字
print "leave C"
#輸出
>>> c = C()
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
按我們的理解,enter A下面輸出應該是基類base中enter base,為什麽是enter B ?? 原因是super跟父類沒有什麽關聯,因此執行的順序是A-->B-->Base
執行過程是:
初始化C()時,先會去調用A的構造方法中的 super(A, self).__init__()
, super(A, self)
返回當前類的繼承順序中A後的一個類B;然後再執行super(B,self).__init()__
,這樣順序執行下去。
super方法可以看出:super()的第一個參數可以是繼承鏈中任意一個類的名字,
1 如果是本身就會依次繼承下一個類;
2 如果是繼承鏈裏之前的類便會無限遞歸下去;
3 如果是繼承鏈裏之後的類便會忽略繼承鏈匯總本身和傳入類之間的類;
Python中深淺拷貝 垃圾回收與 super繼承(六)