新聞中心
c(a/g/w)ll選擇哪個(gè)
熱門頻道
成都創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司是一家服務(wù)多年做網(wǎng)站建設(shè)策劃設(shè)計(jì)制作的公司,為廣大用戶提供了網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站,成都網(wǎng)站設(shè)計(jì),一元廣告,成都做網(wǎng)站選成都創(chuàng)新互聯(lián),貼合企業(yè)需求,高性價(jià)比,滿足客戶不同層次的需求一站式服務(wù)歡迎致電。
首頁
博客
研修院
VIP
APP
問答
下載
社區(qū)
推薦頻道
活動(dòng)
招聘
專題
打開CSDN APP
Copyright ? 1999-2020, CSDN.NET, All Rights Reserved
打開APP
c語言lr文法還是ll文法,編譯原理復(fù)習(xí)題 轉(zhuǎn)載
2021-05-20 05:05:24
Tim Pan
碼齡4年
關(guān)注
一、單項(xiàng)選擇題 概述部分
1.構(gòu)造編譯程序應(yīng)掌握 。D A. 源程序 B. 目標(biāo)語言 C. 編譯方法 D. 以上三項(xiàng)都是 2.編譯程序絕大多數(shù)時(shí)間花在 上。D
A. 出錯(cuò)處理
B. 詞法分析
C. 目標(biāo)代碼生成
D. 表格管理 3.編譯程序是對(duì) 。D
A. 匯編程序的翻譯
B. 高級(jí)語言程序的解釋執(zhí)行
C. 機(jī)器語言的執(zhí)行
D. 高級(jí)語言的翻譯 4. 將編譯程序分成若干“遍”,是為了 。B
A. 提高程序的執(zhí)行效率
B. 使程序的結(jié)構(gòu)更為清晰 C 利用有限的機(jī)器內(nèi)存并提高機(jī)器的執(zhí)行效率 D. 利用有限的機(jī)器內(nèi)存但降低了機(jī)器的執(zhí)行效率
詞法分析部分
1.DFA M(見圖1-1)接受的字集為 。D A. 以0開頭的二進(jìn)制數(shù)組成的集合
B. 以0結(jié)尾的二進(jìn)制數(shù)組成的集合
6cdcbebbe8f9854cde4e92f9afe9313b.png
C. 含奇數(shù)個(gè)0的二進(jìn)制數(shù)組成的集合
D. 含偶數(shù)個(gè)0的二進(jìn)制數(shù)組成的集合
2.詞法分析器的輸出結(jié)果是 。C
A. 單詞的種別編碼
B. 單詞在符號(hào)表中的位置
C. 單詞的種別編碼和自身值
D. 單詞自身值 3.正規(guī)式M1和M2等價(jià)是指 。C A. M1和M2的狀態(tài)數(shù)相等 B. M1和M2的有向邊條數(shù)相等 C. M1和M2所識(shí)別的語言集相等 D. M1和M2狀態(tài)數(shù)和有向邊條數(shù)相等 4.詞法分析器的加工對(duì)象是 。 C A .中間代碼 B .單詞 C .源程序 D .元程序 5.同正規(guī)式(a|b )*等價(jià)的正規(guī)式為 。D A .(a|b)+ B .a(chǎn)*|b* C .(ab)* D .(a*|b*)+ 6. 兩個(gè)DFA 等價(jià)是指: 。 D A. 這兩個(gè)DFA 的狀態(tài)數(shù)相同
B. 這兩個(gè)DFA 的狀態(tài)數(shù)和有向弧條數(shù)都相等
C. 這兩個(gè)DFA 的有向弧條數(shù)相等
D. 這兩個(gè)DFA 接受的語言相同
7. 下列符號(hào)串不可以由符號(hào)集S ={a,b}上的正閉包運(yùn)算產(chǎn)生的是:(A ) A. ε B. a C. aa D. ab 8.稱有限自動(dòng)機(jī)A1和A2等價(jià)是指________。D A .A1和A2都是定義在一個(gè)字母表上的有限自動(dòng)機(jī) B .A1和A2狀態(tài)數(shù)和有向邊數(shù)相等
圖1-1
1
相關(guān)資源:編譯原理賦值語句的翻譯LL文法LR文法簡(jiǎn)單優(yōu)先法-專業(yè)指導(dǎo)文檔類...
文章知識(shí)點(diǎn)與官方知識(shí)檔案匹配
C技能樹首頁概覽
110422 人正在系統(tǒng)學(xué)習(xí)中
打開CSDN APP,看更多技術(shù)內(nèi)容
編譯原理五 LR(1)分析法【C語言實(shí)現(xiàn)】_wangkay88的博客
1、使用 LR 的優(yōu)點(diǎn): (1)LR 分析器能夠構(gòu)造來識(shí)別所有能用上下文無關(guān)文法寫的程序設(shè)計(jì)語言的結(jié)構(gòu)。 (2)LR 分析方法是已知的最一般的無回溯移進(jìn)-歸約方法,它能夠和其他移進(jìn)-歸約方法 一樣有效地實(shí)現(xiàn)。 (3)LR 方法能分析的文法...
lr參數(shù)與C語言函數(shù)參數(shù)的區(qū)別_weixin_30254435的博客
LR參數(shù)是lr自己封裝的一個(gè)鐘對(duì)象, LR參數(shù)的表達(dá)方式:{ParamName}
編譯原理習(xí)題——第2章 文法和語言試卷
第2章 文法和語言試卷 1. 文法:G:S→xSx|y所識(shí)別的語言是(D)。 A. xyx B. (xyx)* C.x*yx* D. xnyxn(n≥0) 2. 給定文法A→bA|ca,為該文法句子的是(C)。 A. bba B. cab C. bca D. cba 3. 文法G產(chǎn)生的(D)的全體是該文法描述的語言。 A. 句型 B. 終結(jié)符集 C. 非終結(jié)符集 D. 句子 4. 若文法G...
繼續(xù)訪問
編譯原理習(xí)題(含答案)——2程序設(shè)計(jì)語言及其文法——哈工大陳鄞配套版本
程序設(shè)計(jì)語言及其文法1 文法:G:S→xSx | y所識(shí)別的語言是( )。 2 給定文法A→bA|ca,為該文法句子的是( )。A. bbaB. cabC. bcaD. Cba 3 設(shè)有文法G[S]:S-S1|S0|Sa|Sc|a|b|c,下列符號(hào)串中是該文法的句子有( )。A. ab0B. a0b01C. a0b0aD. bc10 4 文法G產(chǎn)生的( )的全體是該文法描述的語言。A. ...
繼續(xù)訪問
c語言lr分析器的設(shè)計(jì)與實(shí)現(xiàn)_[源碼和文檔分享]基于LR分析法的簡(jiǎn)單分析法...
通過設(shè)計(jì)、編制、調(diào)試一個(gè)簡(jiǎn)單計(jì)算器程序,加深對(duì)語法及語義分析原理的理解,并實(shí)現(xiàn)詞法分析程序?qū)卧~序列的詞法檢查和分析。 二、課程設(shè)計(jì)內(nèi)容及步驟 本次課程設(shè)計(jì)需要使用 LR 分析法完成簡(jiǎn)單計(jì)算器的設(shè)計(jì),其中算術(shù)表達(dá)式的文法如下: ...
C語言實(shí)現(xiàn)編譯原理的LR分析法,編譯原理LR(0)分析器(C語言).pdf
1LR 分析法 LR LR “ 分析法是一種自底向上進(jìn)行的規(guī)范規(guī)約的語法分析方法, 指 自左向 右掃描和自底向上進(jìn)行歸約”。LR 分析法的一個(gè)主要缺點(diǎn)是,若用手工構(gòu)造分析 LR 器則工作量相當(dāng)大,因此必須求助于自動(dòng)產(chǎn)生 分析器的產(chǎn)生器。
編譯原理 第三章 詞法分析
1、詞法分析器的輸出結(jié)果是單詞的種類編碼和自身值 2、詞法分析器不能發(fā)現(xiàn)括號(hào)不匹配 3、不存在語言能被確定的有窮自動(dòng)機(jī)識(shí)別但不能用正則表達(dá)式表示 4、兩個(gè)有窮自動(dòng)機(jī)等價(jià)實(shí)質(zhì)它們的所識(shí)別的語言相等 5、詞法分析器用于識(shí)別單詞 6、正則表達(dá)式R1和R2等價(jià)是指R1和R2代表同一正則集 7、已知文法G[S]:S-A1, A-A1|S0|0,與G等價(jià)的正規(guī)式是0(1|10)^1 8、與(a...
繼續(xù)訪問
【編譯原理-練習(xí)題-1】概述部分與詞法分析部分選擇,填空,判斷,多選題
一、單項(xiàng)選擇題 1.構(gòu)造編譯程序應(yīng)掌握 (D ) 。 a. 源程序 b. 目標(biāo)語言 c. 編譯方法 d. 以上三項(xiàng)都是 2.編譯程序絕大多數(shù)時(shí)間花在 (D) 上。 a. 出錯(cuò)處理 b. 詞法分析 c. 目標(biāo)代碼生成 d. 表格管理 3.DFA M(見圖1-1)接受的字集為(D ) 。 a. 以0開頭的二進(jìn)制數(shù)組成的集合 b. 以0結(jié)尾的二進(jìn)制數(shù)組成的集合 ...
繼續(xù)訪問
LR中用C語言比較兩個(gè)字符串變量_花露絲雨的博客
6.lr_save_string( "We can see the string:nancy","string1" ); 7.lr_save_string( "We can see the string:nancy","string2" ); 8.lr_output_message("the string1 is %s.",lr_eval_string("{string1}")); ...
c語言字符串變量的比較,LR中用C語言比較兩個(gè)字符串變量.doc_夢(mèng)符佳月...
LR中用C語言比較兩個(gè)字符串變量 Zee的早期文檔.一:以下腳本,定義兩個(gè)一樣的字符數(shù)組,對(duì)比后,打印出result的值: vuser_init() { int result; ? ???char string1[] = "We can see the string:zee"; ...
最新發(fā)布 編譯原理刷題(個(gè)人向)
編譯原理刷題
繼續(xù)訪問
【編譯原理】課后習(xí)題
1.構(gòu)造編譯程序應(yīng)掌握:源程序、目標(biāo)語言、編譯方法 2.編譯程序絕大多數(shù)時(shí)間花在表格管理上 3. 4.一個(gè)程序是正確的,包括兩層含義:一是書寫正確;二是含義正確 (合乎語法規(guī)則、合乎語義規(guī)則) 5.描述高級(jí)語言語法常用的方法有語法樹、BNF范式、擴(kuò)充的BNF范式等 6.程序語言一般可以分為低級(jí)語言和高級(jí)語言兩大類,其中低級(jí)語言通常又稱為面向機(jī)器的語言。面向機(jī)器語言指的是特定計(jì)算機(jī)系統(tǒng)所...
繼續(xù)訪問
C語言實(shí)現(xiàn)編譯原理的LR分析法,實(shí)驗(yàn)三編譯原理綜合實(shí)驗(yàn)報(bào)告——(LR...
注意:本例是利用LR(0)分析來實(shí)現(xiàn)的語法分析,同學(xué)在寫實(shí)驗(yàn)報(bào)告的時(shí)候,在結(jié)果分析這一塊可以選用課堂講過的LR(0)文法來說明驗(yàn)證結(jié)果即可。 同時(shí)附上你所選用的文法對(duì)應(yīng)的LR(0)分析表。
編譯原理總結(jié),看這一篇就夠了!_LeeDuo.的博客_編譯原理
1.詞法分析:對(duì)源程序的字符串進(jìn)行掃描和分解,識(shí)別出每個(gè)單詞符號(hào)。 2.語法分析:根據(jù)語言的語法規(guī)則,把單詞符號(hào)分解成各類語法單位。 3.語義分析與中間代碼生成:對(duì)各種語法范疇進(jìn)行靜態(tài)語義檢查,若正確則進(jìn)行中間代碼翻譯。 4.代碼優(yōu)化:...
C語言LR(1)文法
用C語言編寫,對(duì)一個(gè)LR(1)文法分析,文法為:實(shí)現(xiàn)兩個(gè)數(shù)的加減乘除四則運(yùn)算。并能得出計(jì)算結(jié)果。
熱門推薦 編譯原理習(xí)題(含答案)——3詞法分析——哈工大陳鄞配套版本
詞法分析1 詞法分析器的輸出結(jié)果是( )。A. 單詞自身值B. 單詞在符號(hào)表中的位置C. 單詞的種別編碼 D. 單詞的種別編碼和自身值2 詞法分析器不能( )。A. 識(shí)別出數(shù)值常量B. 過濾源程序中的注釋C. 掃描源程序并識(shí)別記號(hào)D. 發(fā)現(xiàn)括號(hào)不匹配 3 ( )這樣一些語言,它們能被確定的有窮自動(dòng)機(jī)識(shí)別,但不能用正則表達(dá)式表示。A. 存在B. 不存在C. 無法判定是否存在D. 以上答案都不對(duì) 4 ...
繼續(xù)訪問
C--編譯器:C--編譯器,實(shí)現(xiàn)LL(1)\ LR(0)\ SLR \ LR(1)并生成語義分析和MIPS
實(shí)現(xiàn)了自制的C--語言的一遍掃描編譯,包括詞法分析,LR(1)語法分析,屬性文法+中間代碼生成,MIPS編譯生成編譯腳本由Python實(shí)現(xiàn),兼容python2.7與3.7,圖形界面由WPF實(shí)現(xiàn),使用了IronPython進(jìn)行腳本執(zhí)行 支持以下特性: 一種基本類型int 賦值表達(dá)式,循環(huán)/選擇/判斷/跳出語句 函數(shù)定義與函數(shù)調(diào)用 未實(shí)現(xiàn): 浮點(diǎn)數(shù),字符,字符串 斑點(diǎn) 錯(cuò)誤檢查
編譯原理之LR(0)分析算法的c實(shí)現(xiàn)
LR(0)分析器的構(gòu)造算法如下: 對(duì)一個(gè)文法構(gòu)造了它的LR(0)分析表后就可以在LR分析器的總控程序(驅(qū)動(dòng)程序)控制下對(duì)輸入串進(jìn)行分析,即根據(jù)輸入串的當(dāng)前符號(hào)和分析棧的棧頂狀態(tài)查找分析表應(yīng)采取的動(dòng)作,對(duì)狀態(tài)棧和符號(hào)棧進(jìn)行相應(yīng)的操作即移進(jìn)、歸約、接受或報(bào)錯(cuò)。具體說明如下: (1)若ACTION[S,a]=Sj,a為終結(jié)符,則把a(bǔ)移入符號(hào)棧,j移入狀態(tài)棧; (2)若ACTION[S,a]=rj,
繼續(xù)訪問
編譯原理第一章自測(cè)題
第一章 高級(jí)語言與編譯程序概述 一、單項(xiàng)選擇題 1.將編譯程序分成若干個(gè)“遍”是為了____ 。 A. 提高程序的執(zhí)行效率 B. 使程序的結(jié)構(gòu)更加清晰 C. 利用有限的機(jī)器內(nèi)存并提高機(jī)器的執(zhí)行效率 D. 利用有限的機(jī)器內(nèi)存但降低了機(jī)器的執(zhí)行效率 2.構(gòu)造編譯程序應(yīng)掌握 ____ 。 A. 源程序 B. 目標(biāo)語言 C. 編譯方法 D. 以上三項(xiàng)都是 3.編譯程序絕大多數(shù)時(shí)間花在 ____ 上。 A. 出錯(cuò)處理 B. 詞法分析 C. 目標(biāo)代碼生成 D. 管理表格
C語言語法分析程序(編譯原理:LR)
北郵大三編譯原理課程序 注釋很詳細(xì)
用c++實(shí)現(xiàn)LR語法分析器
通過LR分析表及三個(gè)棧形成對(duì)輸入表達(dá)式的判斷! 。
c語言lr文法還是ll文法,編譯原理第五章語法分析課后題
(先補(bǔ)到這里,后面如果有需要的話,垃圾博主還會(huì)回來繼續(xù)更的。。。)5.1 遞歸子程序法屬于()語法分析方法A. 自頂向下B. 自底向上C. 自左向右D. 自右向左5.2 采用確定的自頂向下分析時(shí),必須()A. 消除左遞歸B. 消除右遞歸C. 避免回溯D. 提取左公因子5.3 自上而下語法分析的主要分析動(dòng)作是A. 推導(dǎo)B. 移進(jìn)C. 歸約D. 匹配5.4 一個(gè)字符屬于FOLLOW(S),這個(gè)字符的含...
繼續(xù)訪問
編譯原理,C語言實(shí)現(xiàn)LR(0)分析(擴(kuò)展文法的生成、項(xiàng)目集規(guī)范簇的生成、ACTION GOTO表的生成、句子的分析)
編譯原理,C語言實(shí)現(xiàn)LR(0)分析(擴(kuò)展文法的生成、項(xiàng)目集規(guī)范簇的生成、ACTION GOTO表的生成、句子的分析) (1)根據(jù)提示輸入文法的個(gè)數(shù) (2)輸入文法 (3)擴(kuò)展文法的生成、項(xiàng)目集規(guī)范簇的生成、ACTION GOTO表的生成 (3)分析句子 (4)生成分析過程 C語言實(shí)現(xiàn)LR(0)分析源代碼
繼續(xù)訪問
編譯程序基本原理
編譯程序和解釋程序 人們利用高級(jí)語言與計(jì)算機(jī)進(jìn)行交互, 但計(jì)算機(jī)仍然只能理解和執(zhí)行由 0, 1序列構(gòu)成的機(jī)器語言, 因此高級(jí)程序設(shè)計(jì)語言需要翻譯, 擔(dān)負(fù)這一任務(wù)的程序稱為"語言處理程序", 由于應(yīng)用的不同, 語言之間的翻譯也是多種多樣的. 大致可分為 匯編程序、解釋程序和編譯程序. 用某種高級(jí)語言或匯編語言編寫的程序稱為 源程序, 源程序不能直接在計(jì)算機(jī)上執(zhí)行. 如果源程序是用匯編語言寫的, ...
繼續(xù)訪問
LR腳本用戶自定義C語言函數(shù)
LR腳本實(shí)戰(zhàn):用戶自定義C語言函數(shù) Loadrunner可以使用標(biāo)準(zhǔn)C語言的函數(shù),因此我們可以在腳本中編寫自己的函數(shù)用于調(diào)用,把腳本結(jié)構(gòu)化,更好的進(jìn)行重用。 先看一個(gè)例子: Action() { int i,j; j = 1; for (i=0;i10;i++) { lr_message("i+j=%d",sum(i,j)); j++; } ...
繼續(xù)訪問
編譯原理,第一章緒論
編譯過程和編譯程序結(jié)構(gòu) 五個(gè)階段: 詞法分析 語法分析 語義分析和中間代碼生成 優(yōu)化 目標(biāo)代碼生成 編譯程序的開發(fā) 自編譯:用某種高級(jí)語言編寫自己的編譯程序稱為自編譯, 交叉編譯:用A機(jī)器上的編譯程序來產(chǎn)生可在B機(jī)器上運(yùn)行的目標(biāo)代碼 自展:首先確定一個(gè)非常簡(jiǎn)單的核心語言L0,然后用機(jī)器語言或者匯編語言寫出它的編譯程序T0,再把語言L0擴(kuò)充到L1,用L0編寫L1的編譯程序T1,這樣不斷擴(kuò)展下去...
繼續(xù)訪問
c語言是 ll文法和lr文法哪個(gè)好
c語言lr文法還是ll文法
寫評(píng)論
評(píng)論
收藏
點(diǎn)贊
踩
分享
Python編寫函數(shù):輸出不超過n的所有完美數(shù)(調(diào)用函數(shù)is_perfect,用函數(shù)def per
#!/usr/bin/python
#?-*-?coding:utf-8?-*-
#?@Time????:?2018/6/14?15:30
#?@File????:?Perfect_Numbers.py
"""
完美數(shù)
"""
def?is_perfect(anum):
"""判斷一個(gè)數(shù)是不是完美數(shù)"""
assert?anum??0,?u'完美數(shù)是大于0的整數(shù)'
ll?=?[]
num?=?0
for?i?in?range(1,?anum):
if?anum?%?i?==?0:
ll.append(i)
num?=?sum(ll)
if?num?==?anum:
return?True
else:
return?False
def?perfect_numbers(a):
"""打印不大于輸入?yún)?shù)的所有完美數(shù)"""
temp?=?1?+?a
alist?=?[]
for?i?in?range(1,?temp):
#?global?alist
if?is_perfect(i):
alist.append(i)
if?len(alist)?==?0:
print?u'不大于{0}的時(shí)候沒有完美數(shù)'.format(a)
else:
print?u'不大于{0}的時(shí)候完美數(shù)有:{1}'.format(a,?alist)
if?__name__?==?'__main__':
nums?=?int(raw_input(u'請(qǐng)輸入一個(gè)正整數(shù):'))
perfect_numbers(nums)
用python編寫一個(gè)函數(shù),接收一個(gè)列表參數(shù),函數(shù)返回該列表中所有正數(shù)之和。最后在主主程序中測(cè)試該函數(shù)?
題主你好,
代碼及測(cè)試截圖如下:
希望可以幫到題主, 歡迎追問
后端編程Python3-調(diào)試、測(cè)試和性能剖析(下)
單元測(cè)試(Unit Testing)
為程序編寫測(cè)試——如果做的到位——有助于減少bug的出現(xiàn),并可以提高我們對(duì)程序按預(yù)期目標(biāo)運(yùn)行的信心。通常,測(cè)試并不能保證正確性,因?yàn)閷?duì)大多數(shù)程序而言, 可能的輸入范圍以及可能的計(jì)算范圍是如此之大,只有其中最小的一部分能被實(shí)際地進(jìn) 行測(cè)試。盡管如此,通過仔細(xì)地選擇測(cè)試的方法和目標(biāo),可以提高代碼的質(zhì)量。
大量不同類型的測(cè)試都可以進(jìn)行,比如可用性測(cè)試、功能測(cè)試以及整合測(cè)試等。這里, 我們只講單元測(cè)試一對(duì)單獨(dú)的函數(shù)、類與方法進(jìn)行測(cè)試,確保其符合預(yù)期的行為。
TDD的一個(gè)關(guān)鍵點(diǎn)是,當(dāng)我們想添加一個(gè)功能時(shí)——比如為類添加一個(gè)方法—— 我們首次為其編寫一個(gè)測(cè)試用例。當(dāng)然,測(cè)試將失敗,因?yàn)槲覀冞€沒有實(shí)際編寫該方法?,F(xiàn)在,我們編寫該方法,一旦方法通過了測(cè)試,就可以返回所有測(cè)試,確保我們新添加的代碼沒有任何預(yù)期外的副作用。一旦所有測(cè)試運(yùn)行完畢(包括我們?yōu)樾鹿δ芫帉懙臏y(cè)試),就可以對(duì)我們的代碼進(jìn)行檢查,并有理有據(jù)地相信程序行為符合我們的期望——當(dāng)然,前提是我們的測(cè)試是適當(dāng)?shù)摹?/p>
比如,我們編寫了一個(gè)函數(shù),該函數(shù)在特定的索引位置插入一個(gè)字符串,可以像下面這樣開始我們的TDD:
def insert_at(string, position, insert):
"""Returns a copy of string with insert inserted at the position
string = "ABCDE"
result =[]
for i in range(-2, len(string) + 2):
... result.append(insert_at(string, i,“-”))
result[:5]
['ABC-DE', 'ABCD-E', '-ABCDE','A-BCDE', 'AB-CDE']
result[5:]
['ABC-DE', 'ABCD-E', 'ABCDE-', 'ABCDE-']
"""
return string
對(duì)不返回任何參數(shù)的函數(shù)或方法(通常返回None),我們通常賦予其由pass構(gòu)成的一個(gè)suite,對(duì)那些返回值被試用的,我們或者返回一個(gè)常數(shù)(比如0),或者某個(gè)不變的參數(shù)——這也是我們這里所做的。(在更復(fù)雜的情況下,返回fake對(duì)象可能更有用一一對(duì)這樣的類,提供mock對(duì)象的第三方模塊是可用的。)
運(yùn)行doctest時(shí)會(huì)失敗,并列出每個(gè)預(yù)期內(nèi)的字符串('ABCD-EF'、'ABCDE-F' 等),及其實(shí)際獲取的字符串(所有的都是'ABCD-EF')。一旦確定doctest是充分的和正確的,就可以編寫該函數(shù)的主體部分,在本例中只是簡(jiǎn)單的return string[:position] + insert+string[position:]。(如果我們編寫的是 return string[:position] + insert,之后復(fù)制 string [:position]并將其粘貼在末尾以便減少一些輸入操作,那么doctest會(huì)立即提示錯(cuò)誤。)
Python的標(biāo)準(zhǔn)庫提供了兩個(gè)單元測(cè)試模塊,一個(gè)是doctest,這里和前面都簡(jiǎn)單地提到過,另一個(gè)是unittest。此外,還有一些可用于Python的第三方測(cè)試工具。其中最著名的兩個(gè)是nose (code.google.com/p/python-nose)與py.test (codespeak.net/py/dist/test/test.html), nose 致力于提供比標(biāo)準(zhǔn)的unittest 模塊更廣泛的功能,同時(shí)保持與該模塊的兼容性,py.test則采用了與unittest有些不同的方法,試圖盡可能消除樣板測(cè)試代碼。這兩個(gè)第三方模塊都支持測(cè)試發(fā)現(xiàn),因此沒必要寫一個(gè)總體的測(cè)試程序——因?yàn)槟K將自己搜索測(cè)試程序。這使得測(cè)試整個(gè)代碼樹或某一部分 (比如那些已經(jīng)起作用的模塊)變得很容易。那些對(duì)測(cè)試嚴(yán)重關(guān)切的人,在決定使用哪個(gè)測(cè)試工具之前,對(duì)這兩個(gè)(以及任何其他有吸引力的)第三方模塊進(jìn)行研究都是值 得的。
創(chuàng)建doctest是直截了當(dāng)?shù)模何覀冊(cè)谀K中編寫測(cè)試、函數(shù)、類與方法的docstrings。 對(duì)于模塊,我們簡(jiǎn)單地在末尾添加了 3行:
if __name__ =="__main__":
import doctest
doctest.testmod()
在程序內(nèi)部使用doctest也是可能的。比如,blocks.py程序(其模塊在后面)有自己函數(shù)的doctest,但以如下代碼結(jié)尾:
if __name__== "__main__":
main()
這里簡(jiǎn)單地調(diào)用了程序的main()函數(shù),并且沒有執(zhí)行程序的doctest。要實(shí)驗(yàn)程序的 doctest,有兩種方法。一種是導(dǎo)入doctest模塊,之后運(yùn)行程序---比如,在控制臺(tái)中輸 入 python3 -m doctest blocks.py (在 Wndows 平臺(tái)上,使用類似于 C:Python3 lpython.exe 這樣的形式替代python3)。如果所有測(cè)試運(yùn)行良好,就沒有輸出,因此,我們可能寧愿執(zhí)行python3-m doctest blocks.py-v,因?yàn)檫@會(huì)列出每個(gè)執(zhí)行的doctest,并在最后給出結(jié)果摘要。
另一種執(zhí)行doctest的方法是使用unittest模塊創(chuàng)建單獨(dú)的測(cè)試程序。在概念上, unittest模塊是根據(jù)Java的JUnit單元測(cè)試庫進(jìn)行建模的,并用于創(chuàng)建包含測(cè)試用例的測(cè)試套件。unittest模塊可以基于doctests創(chuàng)建測(cè)試用例,而不需要知道程序或模塊包含的任何事物——只要知道其包含doctest即可。因此,為給blocks.py程序制作一個(gè)測(cè)試套件,我們可以創(chuàng)建如下的簡(jiǎn)單程序(將其稱為test_blocks.py):
import doctest
import unittest
import blocks
suite = unittest.TestSuite()
suite.addTest(doctest.DocTestSuite(blocks))
runner = unittest.TextTestRunner()
print(runner.run(suite))
注意,如果釆用這種方法,程序的名稱上會(huì)有一個(gè)隱含的約束:程序名必須是有效的模塊名。因此,名為convert-incidents.py的程序的測(cè)試不能寫成這樣。因?yàn)閕mport convert-incidents不是有效的,在Python標(biāo)識(shí)符中,連接符是無效的(避開這一約束是可能的,但最簡(jiǎn)單的解決方案是使用總是有效模塊名的程序文件名,比如,使用下劃線替換連接符)。這里展示的結(jié)構(gòu)(創(chuàng)建一個(gè)測(cè)試套件,添加一個(gè)或多個(gè)測(cè)試用例或測(cè)試套件,運(yùn)行總體的測(cè)試套件,輸出結(jié)果)是典型的機(jī)遇unittest的測(cè)試。運(yùn)行時(shí),這一特定實(shí)例產(chǎn)生如下結(jié)果:
...
.............................................................................................................
Ran 3 tests in 0.244s
OK
每次執(zhí)行一個(gè)測(cè)試用例時(shí),都會(huì)輸出一個(gè)句點(diǎn)(因此上面的輸出最前面有3個(gè)句點(diǎn)),之后是一行連接符,再之后是測(cè)試摘要(如果有任何一個(gè)測(cè)試失敗,就會(huì)有更多的輸出信息)。
如果我們嘗試將測(cè)試分離開(典型情況下是要測(cè)試的每個(gè)程序和模塊都有一個(gè)測(cè)試用例),就不要再使用doctests,而是直接使用unittest模塊的功能——尤其是我們習(xí)慣于使用JUnit方法進(jìn)行測(cè)試時(shí)ounittest模塊會(huì)將測(cè)試分離于代碼——對(duì)大型項(xiàng)目(測(cè)試編寫人員與開發(fā)人員可能不一致)而言,這種方法特別有用。此外,unittest單元測(cè)試編寫為獨(dú)立的Python模塊,因此,不會(huì)像在docstring內(nèi)部編寫測(cè)試用例時(shí)受到兼容性和明智性的限制。
unittest模塊定義了 4個(gè)關(guān)鍵概念。測(cè)試夾具是一個(gè)用于描述創(chuàng)建測(cè)試(以及用完之后將其清理)所必需的代碼的術(shù)語,典型實(shí)例是創(chuàng)建測(cè)試所用的一個(gè)輸入文件,最后刪除輸入文件與結(jié)果輸出文件。測(cè)試套件是一組測(cè)試用例的組合。測(cè)試用例是測(cè)試的基本單元—我們很快就會(huì)看到實(shí)例。測(cè)試運(yùn)行者是執(zhí)行一個(gè)或多個(gè)測(cè)試套件的對(duì)象。
典型情況下,測(cè)試套件是通過創(chuàng)建unittest.TestCase的子類實(shí)現(xiàn)的,其中每個(gè)名稱 以“test”開頭的方法都是一個(gè)測(cè)試用例。如果我們需要完成任何創(chuàng)建操作,就可以在一個(gè)名為setUp()的方法中實(shí)現(xiàn);類似地,對(duì)任何清理操作,也可以實(shí)現(xiàn)一個(gè)名為 tearDown()的方法。在測(cè)試內(nèi)部,有大量可供我們使用的unittest.TestCase方法,包括 assertTrue()、assertEqual()、assertAlmostEqual()(對(duì)于測(cè)試浮點(diǎn)數(shù)很有用)、assertRaises() 以及更多,還包括很多對(duì)應(yīng)的逆方法,比如assertFalse()、assertNotEqual()、failIfEqual()、 failUnlessEqual ()等。
unittest模塊進(jìn)行了很好的歸檔,并且提供了大量功能,但在這里我們只是通過一 個(gè)非常簡(jiǎn)單的測(cè)試套件來感受一下該模塊的使用。這里將要使用的實(shí)例,該練習(xí)要求創(chuàng)建一個(gè)Atomic模塊,該模塊可以用作一 個(gè)上下文管理器,以確?;蛘咚懈淖兌紤?yīng)用于某個(gè)列表、集合或字典,或者所有改變都不應(yīng)用。作為解決方案提供的Atomic.py模塊使用30行代碼來實(shí)現(xiàn)Atomic類, 并提供了 100行左右的模塊doctest。這里,我們將創(chuàng)建test_Atomic.py模塊,并使用 unittest測(cè)試替換doctest,以便可以刪除doctest。
在編寫測(cè)試模塊之前,我們需要思考都需要哪些測(cè)試。我們需要測(cè)試3種不同的數(shù)據(jù)類型:列表、集合與字典。對(duì)于列表,需要測(cè)試的是插入項(xiàng)、刪除項(xiàng)或修改項(xiàng)的值。對(duì)于集合,我們必須測(cè)試向其中添加或刪除一個(gè)項(xiàng)。對(duì)于字典,我們必須測(cè)試的是插入一個(gè)項(xiàng)、修改一個(gè)項(xiàng)的值、刪除一個(gè)項(xiàng)。此外,還必須要測(cè)試的是在失敗的情況下,不會(huì)有任何改變實(shí)際生效。
結(jié)構(gòu)上看,測(cè)試不同數(shù)據(jù)類型實(shí)質(zhì)上是一樣的,因此,我們將只為測(cè)試列表編寫測(cè)試用例,而將其他的留作練習(xí)。test_Atomic.py模塊必須導(dǎo)入unittest模塊與要進(jìn)行測(cè)試的Atomic模塊。
創(chuàng)建unittest文件時(shí),我們通常創(chuàng)建的是模塊而非程序。在每個(gè)模塊內(nèi)部,我們定義一個(gè)或多個(gè)unittest.TestCase子類。比如,test_Atomic.py模塊中僅一個(gè)單獨(dú)的 unittest-TestCase子類,也就是TestAtomic (稍后將對(duì)其進(jìn)行講解),并以如下兩行結(jié)束:
if name == "__main__":
unittest.main()
這兩行使得該模塊可以單獨(dú)運(yùn)行。當(dāng)然,該模塊也可以被導(dǎo)入并從其他測(cè)試程序中運(yùn)行——如果這只是多個(gè)測(cè)試套件中的一個(gè),這一點(diǎn)是有意義的。
如果想要從其他測(cè)試程序中運(yùn)行test_Atomic.py模塊,那么可以編寫一個(gè)與此類似的程序。我們習(xí)慣于使用unittest模塊執(zhí)行doctests,比如:
import unittest
import test_Atomic
suite = unittest.TestLoader().loadTestsFromTestCase(test_Atomic.TestAtomic)
runner = unittest.TextTestRunner()
pnnt(runner.run(suite))
這里,我們已經(jīng)創(chuàng)建了一個(gè)單獨(dú)的套件,這是通過讓unittest模塊讀取test_Atomic 模塊實(shí)現(xiàn)的,并且使用其每一個(gè)test*()方法(本實(shí)例中是test_list_success()、test_list_fail(),稍后很快就會(huì)看到)作為測(cè)試用例。
我們現(xiàn)在將查看TestAtomic類的實(shí)現(xiàn)。對(duì)通常的子類(不包括unittest.TestCase 子類),不怎么常見的是,沒有必要實(shí)現(xiàn)初始化程序。在這一案例中,我們將需要建立 一個(gè)方法,但不需要清理方法,并且我們將實(shí)現(xiàn)兩個(gè)測(cè)試用例。
def setUp(self):
self.original_list = list(range(10))
我們已經(jīng)使用了 unittest.TestCase.setUp()方法來創(chuàng)建單獨(dú)的測(cè)試數(shù)據(jù)片段。
def test_list_succeed(self):
items = self.original_list[:]
with Atomic.Atomic(items) as atomic:
atomic.append(1999)
atomic.insert(2, -915)
del atomic[5]
atomic[4]= -782
atomic.insert(0, -9)
self.assertEqual(items,
[-9, 0, 1, -915, 2, -782, 5, 6, 7, 8, 9, 1999])
def test_list_fail(self):
items = self.original_list[:]
with self.assertRaises(AttributeError):
with Atomic.Atomic(items) as atomic:
atomic.append(1999)
atomic.insert(2, -915)
del atomic[5]
atomic[4] = -782
atomic.poop() # Typo
self.assertListEqual(items, self.original_list)
這里,我們直接在測(cè)試方法中編寫了測(cè)試代碼,而不需要一個(gè)內(nèi)部函數(shù),也不再使用unittest.TestCase.assertRaised()作為上下文管理器(期望代碼產(chǎn)生AttributeError)。 最后我們也使用了 Python 3.1 的 unittest.TestCase.assertListEqual()方法。
正如我們已經(jīng)看到的,Python的測(cè)試模塊易于使用,并且極為有用,在我們使用 TDD的情況下更是如此。它們還有比這里展示的要多得多的大量功能與特征——比如,跳過測(cè)試的能力,這有助于理解平臺(tái)差別——并且這些都有很好的文檔支持。缺失的一個(gè)功能——但nose與py.test提供了——是測(cè)試發(fā)現(xiàn),盡管這一特征被期望在后續(xù)的Python版本(或許與Python 3.2—起)中出現(xiàn)。
性能剖析(Profiling)
如果程序運(yùn)行很慢,或者消耗了比預(yù)期內(nèi)要多得多的內(nèi)存,那么問題通常是選擇的算法或數(shù)據(jù)結(jié)構(gòu)不合適,或者是以低效的方式進(jìn)行實(shí)現(xiàn)。不管問題的原因是什么, 最好的方法都是準(zhǔn)確地找到問題發(fā)生的地方,而不只是檢査代碼并試圖對(duì)其進(jìn)行優(yōu)化。 隨機(jī)優(yōu)化會(huì)導(dǎo)致引入bug,或者對(duì)程序中本來對(duì)程序整體性能并沒有實(shí)際影響的部分進(jìn)行提速,而這并非解釋器耗費(fèi)大部分時(shí)間的地方。
在深入討論profiling之前,注意一些易于學(xué)習(xí)和使用的Python程序設(shè)計(jì)習(xí)慣是有意義的,并且對(duì)提高程序性能不無裨益。這些技術(shù)都不是特定于某個(gè)Python版本的, 而是合理的Python程序設(shè)計(jì)風(fēng)格。第一,在需要只讀序列時(shí),最好使用元組而非列表; 第二,使用生成器,而不是創(chuàng)建大的元組和列表并在其上進(jìn)行迭代處理;第三,盡量使用Python內(nèi)置的數(shù)據(jù)結(jié)構(gòu) dicts、lists、tuples 而不實(shí)現(xiàn)自己的自定義結(jié)構(gòu),因?yàn)閮?nèi)置的數(shù)據(jù)結(jié)構(gòu)都是經(jīng)過了高度優(yōu)化的;第四,從小字符串中產(chǎn)生大字符串時(shí), 不要對(duì)小字符串進(jìn)行連接,而是在列表中累積,最后將字符串列表結(jié)合成為一個(gè)單獨(dú)的字符串;第五,也是最后一點(diǎn),如果某個(gè)對(duì)象(包括函數(shù)或方法)需要多次使用屬性進(jìn)行訪問(比如訪問模塊中的某個(gè)函數(shù)),或從某個(gè)數(shù)據(jù)結(jié)構(gòu)中進(jìn)行訪問,那么較好的做法是創(chuàng)建并使用一個(gè)局部變量來訪問該對(duì)象,以便提供更快的訪問速度。
Python標(biāo)準(zhǔn)庫提供了兩個(gè)特別有用的模塊,可以輔助調(diào)査代碼的性能問題。一個(gè)是timeit模塊——該模塊可用于對(duì)一小段Python代碼進(jìn)行計(jì)時(shí),并可用于諸如對(duì)兩個(gè)或多個(gè)特定函數(shù)或方法的性能進(jìn)行比較等場(chǎng)合。另一個(gè)是cProfile模塊,可用于profile 程序的性能——該模塊對(duì)調(diào)用計(jì)數(shù)與次數(shù)進(jìn)行了詳細(xì)分解,以便發(fā)現(xiàn)性能瓶頸所在。
為了解timeit模塊,我們將查看一些小實(shí)例。假定有3個(gè)函數(shù)function_a()、 function_b()、function_c(), 3個(gè)函數(shù)執(zhí)行同樣的計(jì)算,但分別使用不同的算法。如果將這些函數(shù)放于同一個(gè)模塊中(或分別導(dǎo)入),就可以使用timeit模塊對(duì)其進(jìn)行運(yùn)行和比較。下面給出的是模塊最后使用的代碼:
if __name__ == "__main__":
repeats = 1000
for function in ("function_a", "function_b", "function_c"):
t = timeit.Timer("{0}(X, Y)".format(function),"from __main__ import {0}, X, Y".format(function))
sec = t.timeit(repeats) / repeats
print("{function}() {sec:.6f} sec".format(**locals()))
賦予timeit.Timer()構(gòu)造子的第一個(gè)參數(shù)是我們想要執(zhí)行并計(jì)時(shí)的代碼,其形式是字符串。這里,該字符串是“function_a(X,Y)”;第二個(gè)參數(shù)是可選的,還是一個(gè)待執(zhí)行的字符串,這一次是在待計(jì)時(shí)的代碼之前,以便提供一些建立工作。這里,我們從 __main__ (即this)模塊導(dǎo)入了待測(cè)試的函數(shù),還有兩個(gè)作為輸入數(shù)據(jù)傳入的變量(X 與Y),這兩個(gè)變量在該模塊中是作為全局變量提供的。我們也可以很輕易地像從其他模塊中導(dǎo)入數(shù)據(jù)一樣來進(jìn)行導(dǎo)入操作。
調(diào)用timeit.Timer對(duì)象的timeit()方法時(shí),首先將執(zhí)行構(gòu)造子的第二個(gè)參數(shù)(如果有), 之后執(zhí)行構(gòu)造子的第一個(gè)參數(shù)并對(duì)其執(zhí)行時(shí)間進(jìn)行計(jì)時(shí)。timeit.Timer.timeit()方法的返回值是以秒計(jì)數(shù)的時(shí)間,類型是float。默認(rèn)情況下,timeit()方法重復(fù)100萬次,并返回所 有這些執(zhí)行的總秒數(shù),但在這一特定案例中,只需要1000次反復(fù)就可以給出有用的結(jié)果, 因此對(duì)重復(fù)計(jì)數(shù)次數(shù)進(jìn)行了顯式指定。在對(duì)每個(gè)函數(shù)進(jìn)行計(jì)時(shí)后,使用重復(fù)次數(shù)對(duì)總數(shù)進(jìn)行除法操作,就得到了平均執(zhí)行時(shí)間,并在控制臺(tái)中打印出函數(shù)名與執(zhí)行時(shí)間。
function_a() 0.001618 sec
function_b() 0.012786 sec
function_c() 0.003248 sec
在這一實(shí)例中,function_a()顯然是最快的——至少對(duì)于這里使用的輸入數(shù)據(jù)而言。 在有些情況下一一比如輸入數(shù)據(jù)不同會(huì)對(duì)性能產(chǎn)生巨大影響——可能需要使用多組輸入數(shù)據(jù)對(duì)每個(gè)函數(shù)進(jìn)行測(cè)試,以便覆蓋有代表性的測(cè)試用例,并對(duì)總執(zhí)行時(shí)間或平均執(zhí)行時(shí)間進(jìn)行比較。
有時(shí)監(jiān)控自己的代碼進(jìn)行計(jì)時(shí)并不是很方便,因此timeit模塊提供了一種在命令行中對(duì)代碼執(zhí)行時(shí)間進(jìn)行計(jì)時(shí)的途徑。比如,要對(duì)MyModule.py模塊中的函數(shù)function_a()進(jìn)行計(jì)時(shí),可以在控制臺(tái)中輸入如下命令:python3 -m timeit -n 1000 -s "from MyModule import function_a, X, Y" "function_a(X, Y)"(與通常所做的一樣,對(duì) Windows 環(huán)境,我們必須使用類似于C:Python3lpython.exe這樣的內(nèi)容來替換python3)。-m選項(xiàng)用于Python 解釋器,使其可以加載指定的模塊(這里是timeit),其他選項(xiàng)則由timeit模塊進(jìn)行處理。 -n選項(xiàng)指定了循環(huán)計(jì)數(shù)次數(shù),-s選項(xiàng)指定了要建立,最后一個(gè)參數(shù)是要執(zhí)行和計(jì)時(shí)的代碼。命令完成后,會(huì)向控制臺(tái)中打印運(yùn)行結(jié)果,比如:
1000 loops, best of 3: 1.41 msec per loop
之后我們可以輕易地對(duì)其他兩個(gè)函數(shù)進(jìn)行計(jì)時(shí),以便對(duì)其進(jìn)行整體的比較。
cProfile模塊(或者profile模塊,這里統(tǒng)稱為cProfile模塊)也可以用于比較函數(shù) 與方法的性能。與只是提供原始計(jì)時(shí)的timeit模塊不同的是,cProfile模塊精確地展示 了有什么被調(diào)用以及每個(gè)調(diào)用耗費(fèi)了多少時(shí)間。下面是用于比較與前面一樣的3個(gè)函數(shù)的代碼:
if __name__ == "__main__":
for function in ("function_a", "function_b", "function_c"):
cProfile.run("for i in ranged 1000): {0}(X, Y)".format(function))
我們必須將重復(fù)的次數(shù)放置在要傳遞給cProfile.run()函數(shù)的代碼內(nèi)部,但不需要做任何創(chuàng)建,因?yàn)槟K函數(shù)會(huì)使用內(nèi)省來尋找需要使用的函數(shù)與變量。這里沒有使用顯式的print()語句,因?yàn)槟J(rèn)情況下,cProfile.run()函數(shù)會(huì)在控制臺(tái)中打印其輸出。下面給出的是所有函數(shù)的相關(guān)結(jié)果(有些無關(guān)行被省略,格式也進(jìn)行了稍許調(diào)整,以便與頁面適應(yīng)):
1003 function calls in 1.661 CPU seconds
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.003 0.003 1.661 1.661 :1 ( )
1000 1.658 0.002 1.658 0.002 MyModule.py:21 (function_a)
1 0.000 0.000 1.661 1.661 {built-in method exec}
5132003 function calls in 22.700 CPU seconds
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.487 0.487 22.700 22.700 : 1 ( )
1000 0.011 0.000 22.213 0.022 MyModule.py:28(function_b)
5128000 7.048 0.000 7.048 0.000 MyModule.py:29( )
1000 0.00 50.000 0.005 0.000 {built-in method bisectjeft}
1 0.000 0.000 22.700 22.700 {built-in method exec}
1000 0.001 0.000 0.001 0.000 {built-in method len}
1000 15.149 0.015 22.196 0.022 {built-in method sorted}
5129003 function calls in 12.987 CPU seconds
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.205 0.205 12.987 12.987 :l ( )
1000 6.472 0.006 12.782 0.013 MyModule.py:36(function_c)
5128000 6.311 0.000 6.311 0.000 MyModule.py:37( )
1 0.000 0.000 12.987 12.987 {built-in method exec}
ncalls ("調(diào)用的次數(shù)")列列出了對(duì)指定函數(shù)(在filename:lineno(function)中列出) 的調(diào)用次數(shù)?;叵胍幌挛覀冎貜?fù)了 1000次調(diào)用,因此必須將這個(gè)次數(shù)記住。tottime (“總的時(shí)間”)列列出了某個(gè)函數(shù)中耗費(fèi)的總時(shí)間,但是排除了函數(shù)調(diào)用的其他函數(shù)內(nèi)部花費(fèi)的時(shí)間。第一個(gè)percall列列出了對(duì)函數(shù)的每次調(diào)用的平均時(shí)間(tottime // ncalls)。 cumtime ("累積時(shí)間")列出了在函數(shù)中耗費(fèi)的時(shí)間,并且包含了函數(shù)調(diào)用的其他函數(shù)內(nèi)部花費(fèi)的時(shí)間。第二個(gè)percall列列出了對(duì)函數(shù)的每次調(diào)用的平均時(shí)間,包括其調(diào)用的函數(shù)耗費(fèi)的時(shí)間。
這種輸出信息要比timeit模塊的原始計(jì)時(shí)信息富有啟發(fā)意義的多。我們立即可以發(fā)現(xiàn),function_b()與function_c()使用了被調(diào)用5000次以上的生成器,使得它們的速度至少要比function_a()慢10倍以上。并且,function_b()調(diào)用了更多通常意義上的函數(shù),包括調(diào)用內(nèi)置的sorted()函數(shù),這使得其幾乎比function_c()還要慢兩倍。當(dāng)然,timeit() 模塊提供了足夠的信息來查看計(jì)時(shí)上存在的這些差別,但cProfile模塊允許我們了解為什么會(huì)存在這些差別。正如timeit模塊允許對(duì)代碼進(jìn)行計(jì)時(shí)而又不需要對(duì)其監(jiān)控一樣,cProfile模塊也可以做到這一點(diǎn)。然而,從命令行使用cProfile模塊時(shí),我們不能精確地指定要執(zhí)行的 是什么——而只是執(zhí)行給定的程序或模塊,并報(bào)告所有這些的計(jì)時(shí)結(jié)果。需要使用的 命令行是python3 -m cProfile programOrModule.py,產(chǎn)生的輸出信息與前面看到的一 樣,下面給出的是輸出信息樣例,格式上進(jìn)行了一些調(diào)整,并忽略了大多數(shù)行:
10272458 function calls (10272457 primitive calls) in 37.718 CPU secs
ncalls tottime percall cumtime percall filename:lineno(function)
10.000 0.000 37.718 37.718 :1 ( )
10.719 0.719 37.717 37.717 :12( )
1000 1.569 0.002 1.569 0.002 :20(function_a)
1000 0.011 0.000 22.560 0.023 :27(function_b)
5128000 7.078 0.000 7.078 0.000 :28( )
1000 6.510 0.007 12.825 0.013 :35(function_c)
5128000 6.316 0.000 6.316 0.000 :36( )
在cProfile術(shù)語學(xué)中,原始調(diào)用指的就是非遞歸的函數(shù)調(diào)用。
以這種方式使用cProfile模塊對(duì)于識(shí)別值得進(jìn)一步研究的區(qū)域是有用的。比如,這里 我們可以清晰地看到function_b()需要耗費(fèi)更長(zhǎng)的時(shí)間,但是我們?cè)鯓荧@取進(jìn)一步的詳細(xì)資料?我們可以使用cProfile.run("function_b()")來替換對(duì)function_b()的調(diào)用?;蛘呖梢员4嫱耆膒rofile數(shù)據(jù)并使用pstats模塊對(duì)其進(jìn)行分析。要保存profile,就必須對(duì)命令行進(jìn)行稍許修改:python3 -m cProfile -o profileDataFile programOrModule.py。 之后可以對(duì) profile 數(shù)據(jù)進(jìn)行分析,比如啟動(dòng)IDLE,導(dǎo)入pstats模塊,賦予其已保存的profileDataFile,或者也可以在控制臺(tái)中交互式地使用pstats。
下面給出的是一個(gè)非常短的控制臺(tái)會(huì)話實(shí)例,為使其適合頁面展示,進(jìn)行了適當(dāng)調(diào)整,我們自己的輸入則以粗體展示:
$ python3 -m cProfile -o profile.dat MyModule.py
$ python3 -m pstats
Welcome to the profile statistics browser.
% read profile.dat
profile.dat% callers function_b
Random listing order was used
List reduced from 44 to 1 due to restriction
Function was called by...
ncalls tottime cumtime
:27(function_b) - 1000 0.011 22.251 :12( )
profile.dat% callees function_b
Random listing order was used
List reduced from 44 to 1 due to restriction
Function called...
ncalls tottime cumtime
:27(function_b)-
1000 0.005 0.005 built-in method bisectJeft
1000 0.001 0.001 built-in method len
1000 1 5.297 22.234 built-in method sorted
profile.dat% quit
輸入help可以獲取命令列表,help后面跟隨命令名可以獲取該命令的更多信息。比如, help stats將列出可以賦予stats命令的參數(shù)。還有其他一些可用的工具,可以提供profile數(shù)據(jù)的圖形化展示形式,比如 RunSnakeRun (), 該工具需要依賴于wxPython GUI庫。
使用timeit與cProfile模塊,我們可以識(shí)別出我們自己代碼中哪些區(qū)域會(huì)耗費(fèi)超過預(yù)期的時(shí)間;使用cProfile模塊,還可以準(zhǔn)確算岀時(shí)間消耗在哪里。
以上內(nèi)容部分摘自視頻課程 05后端編程Python-19調(diào)試、測(cè)試和性能調(diào)優(yōu)(下) ,更多實(shí)操示例請(qǐng)參照視頻講解。跟著張員外講編程,學(xué)習(xí)更輕松,不花錢還能學(xué)習(xí)真本領(lǐng)。
如何用python編寫一個(gè)求分段函數(shù)的值的程序
1、首先打開python的編輯器軟件,編輯器的選擇可以根據(jù)自己的喜好,之后準(zhǔn)備好一個(gè)空白的python文件:
2、接著在空白的python文件上編寫python程序,這里假設(shè)當(dāng)x>1的時(shí)候,方程為根號(hào)下x加4,當(dāng)x-1時(shí),方程為5乘以x的平方加3。所以在程序的開始需要引入math庫,方便計(jì)算平方和開方,之后在函數(shù)體重寫好表達(dá)式就可以了,最后調(diào)用一下函數(shù),將結(jié)果打印出來:
3、最后點(diǎn)擊軟件內(nèi)的綠色箭頭,運(yùn)行程序,在下方可以看到最終計(jì)算的結(jié)果,以上就是python求分段函數(shù)的過程:
分享名稱:函數(shù)實(shí)驗(yàn)報(bào)告python的簡(jiǎn)單介紹
文章出自:http://fisionsoft.com.cn/article/doogoih.html