Python 代碼優(yōu)化技巧(一)

代碼優(yōu)化Part1<a id="sec-1" name="sec-1"></a>

分享最近看到的關(guān)于代碼優(yōu)化的一些技巧闪盔。

if 判斷的短路特性<a id="sec-1-1" name="sec-1-1"></a>

對(duì)于and蹲堂,應(yīng)該把滿足條件少的放在前面,這樣當(dāng)對(duì)于大量判斷時(shí)楔绞, 滿足條件少的情況直接回導(dǎo)致其后其他表達(dá)式不會(huì)計(jì)算從而節(jié)約時(shí)間(因?yàn)?False and True 還是 False)

import timeit

s1 = """
a = range(2000)
[i for i in a if i % 2 ==0 and i > 1900]
"""

s2 = """
a = range(2000)
[i for i in a if  i > 1900 and i % 2 ==0]
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

運(yùn)行結(jié)果如下:

?  python test6.py
0.248532056808
0.195827960968

# 可以看到s2 表達(dá)式計(jì)算更快读恃, 因?yàn)榇蟛糠智闆r都不滿足 i>1900, 所以這些情況下, i % 2 == 0 也沒(méi)有計(jì)算,從而節(jié)約了時(shí)間

同理對(duì)于or芬膝,把滿足條件多的放在前面悲没。

import timeit

s1 = """
a = range(2000)
[i for i in a if 10 < i <20 or 1000 < i < 2000]
"""

s2 = """
a = range(2000)
[i for i in a if 1000 < i < 2000 or 10 < i <20]
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

運(yùn)行結(jié)果:

0.253124952316
0.202992200851

join 合并字符串<a id="sec-1-2" name="sec-1-2"></a>

join 合并字符串比循環(huán)使用 + 來(lái)合并要快剪决。

import timeit

s1 = """
a = [str(x) for x in range(2000)]
s = ''
for i in a:
    s += i
"""

s2 = """
a = [str(x) for x in range(2000)]
s = ''.join(a)
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

運(yùn)行結(jié)果如下:

python test6.py

0.558945894241
0.422435998917

while 1 和 while True<a id="sec-1-3" name="sec-1-3"></a>

在python2.x里, True 和 False 不是保留的關(guān)鍵字檀训,是一個(gè)全局變量,這意味著你可以這樣

>>> True = 0
>>> True
0
>>> if not True:
...   print '1'
...
1

所以下面這兩種情況:

import timeit

s1 = """
n = 1000000
while 1:
    n -= 1
    if n <= 0: break
"""

s2 = """
n = 1000000
while True:
    n -= 1
    if n <= 0: break
"""

print timeit.timeit(stmt=s1, number=100)
print timeit.timeit(stmt=s2, number=100)

運(yùn)行結(jié)果如下:

?  python test6.py
5.18007302284
6.84624099731

因?yàn)槊看闻袛?while True 的時(shí)候享言, 先要去找到True的值峻凫。

在python3.x里, True 變成了關(guān)鍵字參數(shù)览露,所以上述兩種情況就一樣了荧琼。

cProfile, cStringIO 和 cPickle<a id="sec-1-4" name="sec-1-4"></a>

使用C語(yǔ)言的版本寫(xiě)的擴(kuò)展要比原生的要快。cPickle vs pickle 如下:

import timeit

s1 = """
import cPickle
import pickle
n = range(10000)
cPickle.dumps(n)
"""

s2 = """
import cPickle
import pickle
n = range(10000)
pickle.dumps(n)
"""

print timeit.timeit(stmt=s1, number=100)
print timeit.timeit(stmt=s2, number=100)

運(yùn)行結(jié)果如下:

? python test6.py
0.182178974152
1.70917797089

合理使用生成器<a id="sec-1-5" name="sec-1-5"></a>

區(qū)別<a id="sec-1-5-1" name="sec-1-5-1"></a>

使用()得到的是一個(gè)generator對(duì)象差牛,所需要的內(nèi)存空間與列表的大小無(wú)關(guān)命锄,所以效率會(huì)高一些。

import timeit

s1 = """
[i for i in range (100000)]
"""

s2 = """
(i for i in range(100000))
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

結(jié)果:

?  python test6.py
5.44327497482
0.923446893692

但是對(duì)于需要循環(huán)遍歷的情況:使用迭代器效率反而不高偏化,如下:

import timeit

s1 = """
ls = range(1000000)
def yield_func(ls):
    for i in ls:
        yield i+1
for x in yield_func(ls):
    pass
"""

s2 = """
ls = range(1000000)
def not_yield_func(ls):
    return [i+1 for i in ls]
for x in not_yield_func(ls):
    pass
"""

print timeit.timeit(stmt=s1, number=10)
print timeit.timeit(stmt=s2, number=10)

結(jié)果如下:

?  python test6.py
1.03186702728
1.01472687721

所以使用生成器是一個(gè)權(quán)衡的結(jié)果脐恩,對(duì)于內(nèi)存、速度綜合考慮的結(jié)果侦讨。

xrange<a id="sec-1-5-2" name="sec-1-5-2"></a>

在python2.x里xrange 是純C實(shí)現(xiàn)的生成器驶冒,相對(duì)于range來(lái)說(shuō)苟翻,它不會(huì)一次性計(jì)算出所有值在內(nèi)存中。但它的限制是只能和整型一起工作:你不能使用long或者float骗污。

import 語(yǔ)句的開(kāi)銷<a id="sec-1-6" name="sec-1-6"></a>

import語(yǔ)句有時(shí)候?yàn)榱讼拗扑鼈兊淖饔梅秶蛘吖?jié)省初始化時(shí)間崇猫,被卸載函數(shù)內(nèi)部,雖然python的解釋器不會(huì)重復(fù)import同一個(gè)模塊不會(huì)出錯(cuò)需忿,但重復(fù)導(dǎo)入會(huì)影響部分性能诅炉。
有時(shí)候?yàn)榱藢?shí)現(xiàn)懶加載(即使用的時(shí)候再加載一個(gè)開(kāi)銷很大的模塊),可以這么做:

email = None

def parse_email():
    global email
    if email is None:
        import email
    ...

# 這樣一來(lái)email模塊僅會(huì)被引入一次屋厘,在parse_email()被第一次調(diào)用的時(shí)候涕烧。

參考資源:<a id="sec-2" name="sec-2"></a>

NEXT ctypes<a id="sec-3" name="sec-3"></a>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市擅这,隨后出現(xiàn)的幾起案子澈魄,更是在濱河造成了極大的恐慌,老刑警劉巖仲翎,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痹扇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡溯香,警方通過(guò)查閱死者的電腦和手機(jī)鲫构,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)玫坛,“玉大人结笨,你說(shuō)我怎么就攤上這事∈疲” “怎么了炕吸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)勉痴。 經(jīng)常有香客問(wèn)我赫模,道長(zhǎng),這世上最難降的妖魔是什么蒸矛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任瀑罗,我火速辦了婚禮,結(jié)果婚禮上雏掠,老公的妹妹穿的比我還像新娘斩祭。我一直安慰自己,他們只是感情好乡话,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布摧玫。 她就那樣靜靜地躺著,像睡著了一般绑青。 火紅的嫁衣襯著肌膚如雪席赂。 梳的紋絲不亂的頭發(fā)上吮铭,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音颅停,去河邊找鬼谓晌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛癞揉,可吹牛的內(nèi)容都是我干的纸肉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼喊熟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼柏肪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起芥牌,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤烦味,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后壁拉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谬俄,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年弃理,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了溃论。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痘昌,死狀恐怖钥勋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辆苔,我是刑警寧澤算灸,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站驻啤,受9級(jí)特大地震影響乎婿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜街佑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捍靠。 院中可真熱鬧沐旨,春花似錦、人聲如沸榨婆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)良风。三九已至谊迄,卻和暖如春闷供,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背统诺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工歪脏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粮呢。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓婿失,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親啄寡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豪硅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)挺物,斷路器懒浮,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 注:本文的原文地址為 http://segmentfault.com/a/1190000000618286 許多 ...
    Michael_林閱讀 70,146評(píng)論 3 89
  • 兩本不錯(cuò)的書(shū): 《Python參考手冊(cè)》:對(duì)Python各個(gè)標(biāo)準(zhǔn)模塊,特性介紹的比較詳細(xì)识藤。 《Python核心編程...
    靜熙老師哈哈哈閱讀 3,360評(píng)論 0 80
  • 模板模式 編寫(xiě)優(yōu)秀代碼的一個(gè)要素是避免冗余砚著。在面向?qū)ο缶幊讨校椒ê秃瘮?shù)是我們用來(lái)避免編寫(xiě)冗余代碼的重要工具蹋岩±挡荩回想...
    英武閱讀 1,328評(píng)論 0 50
  • 交友交心 知恩圖報(bào) 人是不知足的,你次次都白給剪个,只要一次拒絕秧骑,就抱怨你不夠意思,忘掉了你所有的好心好意扣囊。...
    許永杰閱讀 216評(píng)論 0 0