做網(wǎng)站能收多少廣告費軟件推廣賺錢一個10元
文章目錄
- Python語言特性
- 1 Python的函數(shù)參數(shù)傳遞
- 2 Python中的元類(metaclass)
- 3 @staticmethod和@classmethod
- 4 類變量和實例變量
- 5 Python自省
- 6 字典推導式
- 7 Python中單下劃線和雙下劃線
- 8 字符串格式化:%和.format
- 9 迭代器和生成器
- 10 `*args` and `**kwargs`
- 11 面向切面編程AOP和裝飾器
- 12 鴨子類型
- 13 Python中重載
- 14 新式類和舊式類
- 15 `__new__`和`__init__`的區(qū)別
- 16 單例模式
- 1 使用`__new__`方法
- 2 共享屬性
- 3 裝飾器版本
- 4 import方法
- 17 Python中的作用域
- 18 GIL線程全局鎖
- 19 協(xié)程
- 20 閉包
- 21 lambda函數(shù)
- 22 Python函數(shù)式編程
- 23 Python里的拷貝
- 24 Python垃圾回收機制
- 1 引用計數(shù)
- 2 標記-清除機制
- 3 分代技術(shù)
- 25 Python的List
- 26 Python的is
- 27 read,readline和readlines
- 28 Python2和3的區(qū)別
- 29 super init
- 30 range and xrange
- Python語言特性
- 1 Python的函數(shù)參數(shù)傳遞
- 2 Python中的元類(metaclass)
- 3 @staticmethod和@classmethod
- 4 類變量和實例變量
- 5 Python自省
- 6 字典推導式
- 7 Python中單下劃線和雙下劃線
- 8 字符串格式化:\x和.format
- 9 迭代器和生成器
- 10 *args and
**kwargs
- 11 面向切面編程AOP和裝飾器
- 12 鴨子類型
- 13 Python中重載
- 14 新式類和舊式類
- 15 __new__和
init
的區(qū)別 - 16 單例模式
- 1 使用__new__方法
- 2 共享屬性
- 3 裝飾器版本
- 4 import方法
- 17 Python中的作用域
- 18 GIL線程全局鎖
- 19 協(xié)程
- 20 閉包
- 21 lambda函數(shù)
- 22 Python函數(shù)式編程
- 23 Python里的拷貝
- 24 Python垃圾回收機制
- 1 引用計數(shù)
- 2 標記-清除機制
- 3 分代技術(shù)
- 25 Python的List
- 26 Python的is
- 27 read,readline和readlines
- 28 Python2和3的區(qū)別
- 29 super init
- 30 range and xrange
Python語言特性
1 Python的函數(shù)參數(shù)傳遞
看兩個例子:
a = 1
def fun(a):a = 2
fun(a)
print a # 1
a = []
def fun(a):a.append(1)
fun(a)
print a # [1]
所有的變量都可以理解是內(nèi)存中一個對象的“引用”,或者,也可以看似c中void*的感覺。
通過id
來看引用a
的內(nèi)存地址可以比較理解:
a = 1
def fun(a):print "func_in",id(a) # func_in 41322472a = 2print "re-point",id(a), id(2) # re-point 41322448 41322448
print "func_out",id(a), id(1) # func_out 41322472 41322472
fun(a)
print a # 1
注:具體的值在不同電腦上運行時可能不同。
可以看到,在執(zhí)行完a = 2
之后,a
引用中保存的值,即內(nèi)存地址發(fā)生變化,由原來1
對象的所在的地址變成了2
這個實體對象的內(nèi)存地址。
而第2個例子a
引用保存的內(nèi)存值就不會發(fā)生變化:
a = []
def fun(a):print "func_in",id(a) # func_in 53629256a.append(1)
print "func_out",id(a) # func_out 53629256
fun(a)
print a # [1]
這里記住的是類型是屬于對象的,而不是變量。而對象有兩種,“可更改”(mutable)與“不可更改”(immutable)對象。在python中,strings, tuples, 和numbers是不可更改的對象,而 list, dict, set 等則是可以修改的對象。(這就是這個問題的重點)
當一個引用傳遞給函數(shù)的時候,函數(shù)自動復制一份引用,這個函數(shù)里的引用和外邊的引用沒有半毛關(guān)系了.所以第一個例子里函數(shù)把引用指向了一個不可變對象,當函數(shù)返回的時候,外面的引用沒半毛感覺.而第二個例子就不一樣了,函數(shù)內(nèi)的引用指向的是可變對象,對它的操作就和定位了指針地址一樣,在內(nèi)存里進行修改.
如果還不明白的話,這里有更好的解釋: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference
2 Python中的元類(metaclass)
這個非常的不常用,但是像ORM這種復雜的結(jié)構(gòu)還是會需要的,詳情請看:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python
3 @staticmethod和@classmethod
Python其實有3個方法,即靜態(tài)方法(staticmethod),類方法(classmethod)和實例方法,如下:
def foo(x):print "executing foo(%s)"%(x)class A(object):def foo(self,x):print "executing foo(%s,%s)"%(self,x)@classmethoddef class_foo(cls,x):print "executing class_foo(%s,%s)"%(cls,x)@staticmethoddef static_foo(x):print "executing static_foo(%s)"%xa=A()
這里先理解下函數(shù)參數(shù)里面的self和cls.這個self和cls是對類或者實例的綁定,對于一般的函數(shù)來說我們可以這么調(diào)用foo(x)
,這個函數(shù)就是最常用的,它的工作跟任何東西(類,實例)無關(guān).對于實例方法,我們知道在類里每次定義方法的時候都需要綁定這個實例,就是foo(self, x)
,為什么要這么做呢?因為實例方法的調(diào)用離不開實例,我們需要把實例自己傳給函數(shù),調(diào)用的時候是這樣的a.foo(x)
(其實是foo(a, x)
).類方法一樣,只不過它傳遞的是類而不是實例,A.class_foo(x)
.注意這里的self和cls可以替換別的參數(shù),但是python的約定是這倆,還是不要改的好.
對于靜態(tài)方法其實和普通的方法一樣,不需要對誰進行綁定,唯一的區(qū)別是調(diào)用的時候需要使用a.static_foo(x)
或者A.static_foo(x)
來調(diào)用.
\ | 實例方法 | 類方法 | 靜態(tài)方法 |
---|---|---|---|
a = A() | a.foo(x) | a.class_foo(x) | a.static_foo(x) |
A | 不可用 | A.class_foo(x) | A.static_foo(x) |
更多關(guān)于這個問題:
- http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python
- https://realpython.com/blog/python/instance-class-and-static-methods-demystified/
4 類變量和實例變量
類變量:
? 是可在類的所有實例之間共享的值(也就是說,它們不是單獨分配給每個實例的)。例如下例中,num_of_instance 就是類變量,用于跟蹤存在著多少個Test 的實例。
實例變量:
實例化之后,每個實例單獨擁有的變量。
class Test(object): num_of_instance = 0 def __init__(self, name): self.name = name Test.num_of_instance += 1 if __name__ == '__main__': print Test.num_of_instance # 0t1 = Test('jack') print Test.num_of_instance # 1t2 = Test('lucy') print t1.name , t1.num_of_instance # jack 2print t2.name , t2.num_of_instance # lucy 2
補充的例子
class Person:name="aaa"p1=Person()
p2=Person()
p1.name="bbb"
print p1.name # bbb
print p2.name # aaa
print Person.name # aaa
這里p1.name="bbb"
是實例調(diào)用了類變量,這其實和上面第一個問題一樣,就是函數(shù)傳參的問題,p1.name
一開始是指向的類變量name="aaa"
,但是在實例的作用域里把類變量的引用改變了,就變成了一個實例變量,self.name不再引用Person的類變量name了.
可以看看下面的例子:
class Person:name=[]p1=Person()
p2=Person()
p1.name.append(1)
print p1.name # [1]
print p2.name # [1]
print Person.name # [1]
參考:http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block
5 Python自省
這個也是python彪悍的特性.
自省就是面向?qū)ο蟮恼Z言所寫的程序在運行時,所能知道對象的類型.簡單一句就是運行時能夠獲得對象的類型.比如type(),dir(),getattr(),hasattr(),isinstance().
a = [1,2,3]
b = {'a':1,'b':2,'c':3}
c = True
print type(a),type(b),type(c) # <type 'list'> <type 'dict'> <type 'bool'>
print isinstance(a,list) # True
6 字典推導式
可能你見過列表推導時,卻沒有見過字典推導式,在2.7中才加入的:
d = {key: value for (key, value) in iterable}
7 Python中單下劃線和雙下劃線
>>> class MyClass():
... def __init__(self):
... self.__superprivate = "Hello"
... self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
__foo__
:一種約定,Python內(nèi)部的名字,用來區(qū)別其他用戶自定義的命名,以防沖突,就是例如__init__()
,__del__()
,__call__()
這些特殊方法
_foo
:一種約定,用來指定變量私有.程序員用來指定私有變量的一種方式.不能用from module import * 導入,其他方面和公有一樣訪問;
__foo
:這個有真正的意義:解析器用_classname__foo
來代替這個名字,以區(qū)別和其他類相同的命名,它無法直接像公有成員一樣隨便訪問,通過對象名._類名__xxx這樣的方式可以訪問.
詳情見:http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python
或者: http://www.zhihu.com/question/19754941
8 字符串格式化:%和.format
.format在許多方面看起來更便利.對于%
最煩人的是它無法同時傳遞一個變量和元組.你可能會想下面的代碼不會有什么問題:
"hi there %s" % name
但是,如果name恰好是(1,2,3),它將會拋出一個TypeError異常.為了保證它總是正確的,你必須這樣做:
"hi there %s" % (name,) # 提供一個單元素的數(shù)組而不是一個參數(shù)
但是有點丑…format就沒有這些問題.你給的第二個問題也是這樣,.format好看多了.
你為什么不用它?
- 不知道它(在讀這個之前)
- 為了和Python2.5兼容(譬如logging庫建議使用
%
(issue #4))
http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format
9 迭代器和生成器
這個是stackoverflow里python排名第一的問題,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python
這是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html
這里有個關(guān)于生成器的創(chuàng)建問題面試官有考:
問: 將列表生成式中[]改成() 之后數(shù)據(jù)結(jié)構(gòu)是否改變?
答案:是,從列表變?yōu)樯善?/p>
>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000028F8B774200>
通過列表生成式,可以直接創(chuàng)建一個列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。而且,創(chuàng)建一個包含百萬元素的列表,不僅是占用很大的內(nèi)存空間,如:我們只需要訪問前面的幾個元素,后面大部分元素所占的空間都是浪費的。因此,沒有必要創(chuàng)建完整的列表(節(jié)省大量內(nèi)存空間)。在Python中,我們可以采用生成器:邊循環(huán),邊計算的機制—>generator
10 *args
and **kwargs
用*args
和**kwargs
只是為了方便并沒有強制使用它們.
當你不確定你的函數(shù)里將要傳遞多少參數(shù)時你可以用*args
.例如,它可以傳遞任意數(shù)量的參數(shù):
>>> def print_everything(*args):for count, thing in enumerate(args):
... print '{0}. {1}'.format(count, thing)
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage
相似的,**kwargs
允許你使用沒有事先定義的參數(shù)名:
>>> def table_things(**kwargs):
... for name, value in kwargs.items():
... print '{0} = {1}'.format(name, value)
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit
你也可以混著用.命名參數(shù)首先獲得參數(shù)值然后所有的其他參數(shù)都傳遞給*args
和**kwargs
.命名參數(shù)在列表的最前端.例如:
def table_things(titlestring, **kwargs)
*args
和**kwargs
可以同時在函數(shù)的定義中,但是*args
必須在**kwargs
前面.
當調(diào)用函數(shù)時你也可以用*
和**
語法.例如:
>>> def print_three_things(a, b, c):
... print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)a = aardvark, b = baboon, c = cat
就像你看到的一樣,它可以傳遞列表(或者元組)的每一項并把它們解包.注意必須與它們在函數(shù)里的參數(shù)相吻合.當然,你也可以在函數(shù)定義或者函數(shù)調(diào)用時用*.
http://stackoverflow.com/questions/3394835/args-and-kwargs
11 面向切面編程AOP和裝飾器
這個AOP一聽起來有點懵,同學面阿里的時候就被問懵了…
裝飾器是一個很著名的設(shè)計模式,經(jīng)常被用于有切面需求的場景,較為經(jīng)典的有插入日志、性能測試、事務(wù)處理等。裝飾器是解決這類問題的絕佳設(shè)計,有了裝飾器,我們就可以抽離出大量函數(shù)中與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用。概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能。
這個問題比較大,推薦: http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python
中文: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/3/README.html
12 鴨子類型
“當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子?!?/p>
我們并不關(guān)心對象是什么類型,到底是不是鴨子,只關(guān)心行為。
比如在python中,有很多file-like的東西,比如StringIO,GzipFile,socket。它們有很多相同的方法,我們把它們當作文件使用。
又比如list.extend()方法中,我們并不關(guān)心它的參數(shù)是不是list,只要它是可迭代的,所以它的參數(shù)可以是list/tuple/dict/字符串/生成器等.
鴨子類型在動態(tài)語言中經(jīng)常使用,非常靈活,使得python不像java那樣專門去弄一大堆的設(shè)計模式。
13 Python中重載
引自知乎:http://www.zhihu.com/question/20053359
函數(shù)重載主要是為了解決兩個問題。
- 可變參數(shù)類型。
- 可變參數(shù)個數(shù)。
另外,一個基本的設(shè)計原則是,僅僅當兩個函數(shù)除了參數(shù)類型和參數(shù)個數(shù)不同以外,其功能是完全相同的,此時才使用函數(shù)重載,如果兩個函數(shù)的功能其實不同,那么不應(yīng)當使用重載,而應(yīng)當使用一個名字不同的函數(shù)。
好吧,那么對于情況 1 ,函數(shù)功能相同,但是參數(shù)類型不同,python 如何處理?答案是根本不需要處理,因為 python 可以接受任何類型的參數(shù),如果函數(shù)的功能相同,那么不同的參數(shù)類型在 python 中很可能是相同的代碼,沒有必要做成兩個不同函數(shù)。
那么對于情況 2 ,函數(shù)功能相同,但參數(shù)個數(shù)不同,python 如何處理?大家知道,答案就是缺省參數(shù)。對那些缺少的參數(shù)設(shè)定為缺省參數(shù)即可解決問題。因為你假設(shè)函數(shù)功能相同,那么那些缺少的參數(shù)終歸是需要用的。
好了,鑒于情況 1 跟 情況 2 都有了解決方案,python 自然就不需要函數(shù)重載了。
14 新式類和舊式類
這個面試官問了,我說了老半天,不知道他問的真正意圖是什么.
stackoverflow
這篇文章很好的介紹了新式類的特性: http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html
新式類很早在2.2就出現(xiàn)了,所以舊式類完全是兼容的問題,Python3里的類全部都是新式類.這里有一個MRO問題可以了解下(新式類繼承是根據(jù)C3算法,舊式類是深度優(yōu)先),<Python核心編程>里講的也很多.
一個舊式類的深度優(yōu)先的例子
class A():def foo1(self):print "A"
class B(A):def foo2(self):pass
class C(A):def foo1(self):print "C"
class D(B, C):passd = D()
d.foo1()# A
按照經(jīng)典類的查找順序從左到右深度優(yōu)先
的規(guī)則,在訪問d.foo1()
的時候,D這個類是沒有的…那么往上查找,先找到B,里面沒有,深度優(yōu)先,訪問A,找到了foo1(),所以這時候調(diào)用的是A的foo1(),從而導致C重寫的foo1()被繞過
15 __new__
和__init__
的區(qū)別
這個__new__
確實很少見到,先做了解吧.
__new__
是一個靜態(tài)方法,而__init__
是一個實例方法.__new__
方法會返回一個創(chuàng)建的實例,而__init__
什么都不返回.- 只有在
__new__
返回一個cls的實例時后面的__init__
才能被調(diào)用. - 當創(chuàng)建一個新實例時調(diào)用
__new__
,初始化一個實例時用__init__
.
stackoverflow
ps: __metaclass__
是創(chuàng)建類時起作用.所以我們可以分別使用__metaclass__
,__new__
和__init__
來分別在類創(chuàng)建,實例創(chuàng)建和實例初始化的時候做一些小手腳.
16 單例模式
? 單例模式是一種常用的軟件設(shè)計模式。在它的核心結(jié)構(gòu)中只包含一個被稱為單例類的特殊類。通過單例模式可以保證系統(tǒng)中一個類只有一個實例而且該實例易于外界訪問,從而方便對實例個數(shù)的控制并節(jié)約系統(tǒng)資源。如果希望在系統(tǒng)中某個類的對象只能存在一個,單例模式是最好的解決方案。
__new__()
在__init__()
之前被調(diào)用,用于生成實例對象。利用這個方法和類的屬性的特點可以實現(xiàn)設(shè)計模式的單例模式。單例模式是指創(chuàng)建唯一對象,單例模式設(shè)計的類只能實例
這個絕對??及?絕對要記住1~2個方法,當時面試官是讓手寫的.
1 使用__new__
方法
class Singleton(object):def __new__(cls, *args, **kw):if not hasattr(cls, '_instance'):orig = super(Singleton, cls)cls._instance = orig.__new__(cls, *args, **kw)return cls._instanceclass MyClass(Singleton):a = 1
2 共享屬性
創(chuàng)建實例時把所有實例的__dict__
指向同一個字典,這樣它們具有相同的屬性和方法.
class Borg(object):_state = {}def __new__(cls, *args, **kw):ob = super(Borg, cls).__new__(cls, *args, **kw)ob.__dict__ = cls._statereturn obclass MyClass2(Borg):a = 1
3 裝飾器版本
def singleton(cls):instances = {}def getinstance(*args, **kw):if cls not in instances:instances[cls] = cls(*args, **kw)return instances[cls]return getinstance@singleton
class MyClass:...
4 import方法
作為python的模塊是天然的單例模式
# mysingleton.py
class My_Singleton(object):def foo(self):passmy_singleton = My_Singleton()# to use
from mysingleton import my_singletonmy_singleton.foo()
單例模式伯樂在線詳細解釋
17 Python中的作用域
Python 中,一個變量的作用域總是由在代碼中被賦值的地方所決定的。
當 Python 遇到一個變量的話他會按照這樣的順序進行搜索:
本地作用域(Local)→當前作用域被嵌入的本地作用域(Enclosing locals)→全局/模塊作用域(Global)→內(nèi)置作用域(Built-in)
18 GIL線程全局鎖
線程全局鎖(Global Interpreter Lock),即Python為了保證線程安全而采取的獨立線程運行的限制,說白了就是一個核只能在同一時間運行一個線程.對于io密集型任務(wù),python的多線程起到作用,但對于cpu密集型任務(wù),python的多線程幾乎占不到任何優(yōu)勢,還有可能因為爭奪資源而變慢。
見Python 最難的問題
解決辦法就是多進程和下面的協(xié)程(協(xié)程也只是單CPU,但是能減小切換代價提升性能).
19 協(xié)程
知乎被問到了,呵呵噠,跪了
簡單點說協(xié)程是進程和線程的升級版,進程和線程都面臨著內(nèi)核態(tài)和用戶態(tài)的切換問題而耗費許多切換時間,而協(xié)程就是用戶自己控制切換的時機,不再需要陷入系統(tǒng)的內(nèi)核態(tài).
Python里最常見的yield就是協(xié)程的思想!可以查看第九個問題.
20 閉包
閉包(closure)是函數(shù)式編程的重要的語法結(jié)構(gòu)。閉包也是一種組織代碼的結(jié)構(gòu),它同樣提高了代碼的可重復使用性。
當一個內(nèi)嵌函數(shù)引用其外部作作用域的變量,我們就會得到一個閉包. 總結(jié)一下,創(chuàng)建一個閉包必須滿足以下幾點:
- 必須有一個內(nèi)嵌函數(shù)
- 內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量
- 外部函數(shù)的返回值必須是內(nèi)嵌函數(shù)
感覺閉包還是有難度的,幾句話是說不明白的,還是查查相關(guān)資料.
重點是函數(shù)運行后并不會被撤銷,就像16題的instance字典一樣,當函數(shù)運行完后,instance并不被銷毀,而是繼續(xù)留在內(nèi)存空間里.這個功能類似類里的類變量,只不過遷移到了函數(shù)上.
閉包就像個空心球一樣,你知道外面和里面,但你不知道中間是什么樣.
21 lambda函數(shù)
其實就是一個匿名函數(shù),為什么叫l(wèi)ambda?因為和后面的函數(shù)式編程有關(guān).
推薦: 知乎
22 Python函數(shù)式編程
這個需要適當?shù)牧私庖幌掳?畢竟函數(shù)式編程在Python中也做了引用.
推薦: 酷殼
python中函數(shù)式編程支持:
filter 函數(shù)的功能相當于過濾器。調(diào)用一個布爾函數(shù)bool_func
來迭代遍歷每個seq中的元素;返回一個使bool_seq
返回值為true的元素的序列。
>>>a = [1,2,3,4,5,6,7]
>>>b = filter(lambda x: x > 5, a)
>>>print b
>>>[6,7]
map函數(shù)是對一個序列的每個項依次執(zhí)行函數(shù),下面是對一個序列每個項都乘以2:
>>> a = map(lambda x:x*2,[1,2,3])
>>> list(a)
[2, 4, 6]
reduce函數(shù)是對一個序列的每個項迭代調(diào)用函數(shù),下面是求3的階乘:
>>> reduce(lambda x,y:x*y,range(1,4))
6
23 Python里的拷貝
引用和copy(),deepcopy()的區(qū)別
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']數(shù)組對象print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d輸出結(jié)果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
24 Python垃圾回收機制
Python GC主要使用引用計數(shù)(reference counting)來跟蹤和回收垃圾。在引用計數(shù)的基礎(chǔ)上,通過“標記-清除”(mark and sweep)解決容器對象可能產(chǎn)生的循環(huán)引用問題,通過“分代回收”(generation collection)以空間換時間的方法提高垃圾回收效率。
1 引用計數(shù)
PyObject是每個對象必有的內(nèi)容,其中ob_refcnt
就是做為引用計數(shù)。當一個對象有新的引用時,它的ob_refcnt
就會增加,當引用它的對象被刪除,它的ob_refcnt
就會減少.引用計數(shù)為0時,該對象生命就結(jié)束了。
優(yōu)點:
- 簡單
- 實時性
缺點:
- 維護引用計數(shù)消耗資源
- 循環(huán)引用
2 標記-清除機制
基本思路是先按需分配,等到?jīng)]有空閑內(nèi)存的時候從寄存器和程序棧上的引用出發(fā),遍歷以對象為節(jié)點、以引用為邊構(gòu)成的圖,把所有可以訪問到的對象打上標記,然后清掃一遍內(nèi)存空間,把所有沒標記的對象釋放。
3 分代技術(shù)
分代回收的整體思想是:將系統(tǒng)中的所有內(nèi)存塊根據(jù)其存活時間劃分為不同的集合,每個集合就成為一個“代”,垃圾收集頻率隨著“代”的存活時間的增大而減小,存活時間通常利用經(jīng)過幾次垃圾回收來度量。
Python默認定義了三代對象集合,索引數(shù)越大,對象存活時間越長。
舉例:
當某些內(nèi)存塊M經(jīng)過了3次垃圾收集的清洗之后還存活時,我們就將內(nèi)存塊M劃到一個集合A中去,而新分配的內(nèi)存都劃分到集合B中去。當垃圾收集開始工作時,大多數(shù)情況都只對集合B進行垃圾回收,而對集合A進行垃圾回收要隔相當長一段時間后才進行,這就使得垃圾收集機制需要處理的內(nèi)存少了,效率自然就提高了。在這個過程中,集合B中的某些內(nèi)存塊由于存活時間長而會被轉(zhuǎn)移到集合A中,當然,集合A中實際上也存在一些垃圾,這些垃圾的回收會因為這種分代的機制而被延遲。
25 Python的List
推薦: http://www.jianshu.com/p/J4U6rR
26 Python的is
is是對比地址,==是對比值
27 read,readline和readlines
- read 讀取整個文件
- readline 讀取下一行,使用生成器方法
- readlines 讀取整個文件到一個迭代器以供我們遍歷
28 Python2和3的區(qū)別
推薦:Python 2.7.x 與 Python 3.x 的主要差異
29 super init
super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven’t already.
Note that the syntax changed in Python 3.0: you can just say super().__init__
() instead of super(ChildB, self).__init__
() which IMO is quite a bit nicer.
http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods
Python2.7中的super方法淺見
30 range and xrange
都在循環(huán)時使用,xrange內(nèi)存性能更好。
for i in range(0, 20):
for i in xrange(0, 20):
What is the difference between range and xrange functions in Python 2.X?
range creates a list, so if you do range(1, 10000000) it creates a list in memory with 9999999 elements.
xrange is a sequence object that evaluates lazily.
http://stackoverflow.com/questions/94935/what-is-the-difference-between-range-and-xrange-functions-in-python-2-x