ABSP第8章: 練手項目2則

假如說你是35個學生的地理老師, 現在想做一個隨堂小測考一下美國各個州的首府. 當然了, 班裡面有幾個壞傢伙, 你不敢保證他們不會作弊. 所以你想把試卷題目的順序打亂, 這樣的話每一個人的卷子都是彼此不同的, 想抄也沒法抄. 當然如果要手動實現這個目的會非常的麻煩, 好在有python.

和上一個練手計劃一樣,把需求拆分成如下部分

  • 建立35個不同的試卷
  • 每個試卷有50道單選題, 題目順序隨機
  • 每道題有1個正確答案, 3個錯誤答案, 答案排列順序隨機
  • 把35份試卷寫進35個文本文檔裡面
  • 把35份答案寫進另外35個文本文檔裡面

代碼實現方面包括下面的內容

  • 把各個州和相應的首府存成一個字典
  • 用open(), write()和close()來書寫試卷文件以及答案文件
  • 用random.shuffle()把問題和選項順序打亂

第1步: 把考試題目數據存進字典裡面

最開始 還是應該先建立一個骨架. 然後首先寫入我們的測驗數據. 新建一個文件randomQuizGenerator.py, 程序如下:

#! python3 # randomQuizGenerator.py - Creates quizzes with questions and answers in # random order, along with the answer key.import random # The quiz data. Keys are states and values are their capitals.capitals = {Alabama: Montgomery, Alaska: Juneau, Arizona: Phoenix, Arkansas: Little Rock, California: Sacramento, Colorado: Denver, Connecticut: Hartford, Delaware: Dover, Florida: Tallahassee, Georgia: Atlanta, Hawaii: Honolulu, Idaho: Boise, Illinois: Springfield, Indiana: Indianapolis, Iowa: Des Moines, Kansas: Topeka, Kentucky: Frankfort, Louisiana: Baton Rouge, Maine: Augusta, Maryland: Annapolis, Massachusetts: Boston, Michigan: Lansing, Minnesota: Saint Paul, Mississippi: Jackson, Missouri: Jefferson City, Montana: Helena, Nebraska: Lincoln, Nevada: Carson City, New Hampshire: Concord, New Jersey: Trenton, New Mexico: Santa Fe, New York: Albany, North Carolina: Raleigh, North Dakota: Bismarck, Ohio: Columbus, Oklahoma: Oklahoma City, Oregon: Salem, Pennsylvania: Harrisburg, Rhode Island: Providence, South Carolina: Columbia, South Dakota: Pierre, Tennessee: Nashville, Texas: Austin, Utah: Salt Lake City, Vermont: Montpelier, Virginia: Richmond, Washington: Olympia, West Virginia: Charleston, Wisconsin: Madison, Wyoming: Cheyenne} # Generate 35 quiz files.for quizNum in range(35): # TODO: Create the quiz and answer key files. # TODO: Write out the header for the quiz. # TODO: Shuffle the order of the states. # TODO: Loop through all 50 states, making a question for each.

鑒於程序需要對題目和選項隨機分配, 所以我們要import random這個模塊. capital這個變數是一個字典變數, 裡面美國各個州作為key, 而對應的首府作為value. 考慮到你需要建立35份試卷, 生成試題的程序會在一個循環里運行35次. (根據題目數量可以修正這個數字)

第2步: 新建一個試題文件,並打亂答案的順序

現在需要開始填充各個todo了.

loop裡面的程序會運行35次, 所以你只需要關注其中的一次就好. 首先考慮怎樣建立一個試卷文件. 一個試卷文件需要有一個自己的文件名, 並有自己的標準文件頭(比如供學生填寫姓名,日期, 課程章節的地方). 之後你就該開始把州的順序打亂了, 這個打亂以後州的順序使我們遲些建立題目以及答案的依據.

在程序的第一個todo下面添加下面的代碼:

# Create the quiz and answer key files. quizFile = open(capitalsquiz%s.txt % (quizNum + 1), w) answerKeyFile = open(capitalsquiz_answers%s.txt % (quizNum + 1), w) # Write out the header for the quiz. quizFile.write(Name:

Date:

Period:

) quizFile.write(( * 20) + State Capitals Quiz (Form %s) % (quizNum + 1)) quizFile.write(

) # Shuffle the order of the states. states = list(capitals.keys()) random.shuffle(states)

試卷的名字設置為capitalsquiz<N>.txt, 其中<N>由循環的quizNum+1決定. 同樣由這個數值決定的, 還有答案文件: capitalsquiz_answers<N>.txt. 每做一次循環, 兩個文件名中的%s會被quizNum+1替換. (這和print()里的字元替換很像). 這樣一來, 第一次循環的時候得到的文件就是capitalsquiz1.txt和capitalsquiz_answers.txt. 這些文件名作為參數交給open(), 在w寫入模式下打開.

# Write out the header for the quiz.下面的三行給試卷開頭寫入了文件頭, 其中包括填寫考生信息的, 試卷標題的以及結尾的兩個換行.

最後,先用list(capitals.keys())生成一個由capitals所有鍵組成的列表, 隨後對這個列表作shuffle. 把列表內的順序打亂.

第3步: 生成備選項

現在是時候開始準備試卷內容了. 首先是準備一個問題的A到D選項. 你需要再寫一個for循環, 這個for循環負責生成每一個問題, 總共生成50次. 每個循環裡面又有一個for循環用來生成多選題的答案. 程序如下(放在第二個todo下面):

# Loop through all 50 states, making a question for each. for questionNum in range(50): # Get right and wrong answers.? correctAnswer = capitals[states[questionNum]]? wrongAnswers = list(capitals.values())? del wrongAnswers[wrongAnswers.index(correctAnswer)]? wrongAnswers = random.sample(wrongAnswers, 3)? answerOptions = wrongAnswers + [correctAnswer]? random.shuffle(answerOptions) # TODO: Write the question and answer options to the quiz file. # TODO: Write the answer key to a file.

正確答案就好說, 直接根據capitals這個字典變數就可以拿到(1). 錯誤答案會有些複雜. 首先通過list(capitals.values())拿到capitals里所有value的list(2), 之後, 從中去掉這道題的正確答案(3). 在剩下的答案列表裡面隨機取3個. random.sample()這個方法可以完成"隨機抽取3個"這個需求. 這個函數第一個參數是抽取來源的list, 第二個參數是抽取的數量. 最後, 記得把正確答案和錯誤答案合併成一個答案列表, 對這個答案列表shuffle一次(6) 免得所有的題目正確答案都是D.

第4步: 把內容分別寫入問卷和答案文件

接下來要做的工作就是把問卷和答卷分別寫入各自的文件了. 輸入如下代碼:

for questionNum in range(50): --snip-- # Write the question and the answer options to the quiz file. quizFile.write(%s. What is the capital of %s?
% (questionNum + 1, states[questionNum]))? for i in range(4):? quizFile.write( %s. %s
% (ABCD[i], answerOptions[i])) quizFile.write(
) # Write the answer key to a file.? answerKeyFile.write(%s. %s
% (questionNum + 1, ABCD[ answerOptions.index(correctAnswer)])) quizFile.close() answerKeyFile.close()

注意(1),(2)和(3)都還是在最外層的for裡面. (1)的for循環會在0到3之間遍歷, (2)的ABCD[i]把ABCD作為一個數組,根據i從0到3依次返回A, B, C和D.

在(3)這裡answerOptions.index(correctAnswer)是使用correctAnswer的值在answerOptions這個list裡面找到對應的index(0到3),根據0到3的index轉換為A-D中的一個字母作為答案, 寫進答案文件.

在你運行上面的程序以後, 你的capitalquiz1.txt應該看起來像下面一樣. 當然由於隨機化的原因, 排列的順序會有所不同.

Name:Date:Period: State Capitals Quiz (Form 1)1. What is the capital of West Virginia? A. Hartford B. Santa Fe C. Harrisburg D. Charleston2. What is the capital of Colorado? A. Raleigh B. Harrisburg C. Denver D. Lincoln--snip--

而答卷文件看起來會是這樣:

The corresponding capitalsquiz_answers1.txt text file will look like this:1. D2. C3. A4. C--snip--

練手項目2: 多重剪貼板

假如現在你需要填寫一個表單, 上面有很多的項目, 你很煩躁. 雖然用剪貼板可以讓你不用一個字一個字的打進去, 但是你還是要選擇一段文字, ctrl+c, 切換窗口,ctrl+v, 切換窗口, 如此循環. 如果你把幾次的剪切做完, 再切換過去一次貼出去. 這樣至少可以少切換幾次窗口.

你可以寫一個python程序去記錄多個文本內容. 讓我們把這個多重剪貼板命名為mcb.pyw. (pyw文件在運行的時候不會出現terminal窗口, 關於這個的具體說明見附錄B)

這個程序可以把特定的文本內容用一個關鍵字存儲起來. 比如, 你運行py mcb.pyw save spam, 剪貼板裡面的文字就會被存到spam這個關鍵字下面. 另外當你運行py mcb.pyw list的時候, 程序會把所有的關鍵字列表放到剪貼板里輸出.

程序功能需求列表:

  • 檢查命令行參數是否提供了關鍵字
  • 如果有save參數, 那就把剪貼板內容存入對應的關鍵字名下
  • 如果參數是list, 把所有關鍵字列表貼近剪貼板
  • 否則, 把關鍵字對應的內容貼近剪貼板

代碼需要實現的內容:

  • 從sys.argv讀取命令行參數
  • 對剪貼板進行讀寫
  • 將參數保存進shelf文件

如果你用的是windows, 執行這個代碼會很容易. 新建一個mcb.bat在裡面寫入

@pyw.exe C:Python32mcb.pyw %*

以後就在開始>運行裡面運行"mcb.bat 參數"就可以了

第1步:程序骨架, 設置shelf

#! python3 # mcb.pyw - Saves and loads pieces of text to the clipboard.? # Usage: py.exe mcb.pyw save <keyword> - Saves clipboard to keyword. # py.exe mcb.pyw <keyword> - Loads keyword to clipboard. # py.exe mcb.pyw list - Loads all keywords to clipboard.? import shelve, pyperclip, sys? mcbShelf = shelve.open(mcb) # TODO: Save clipboard content. # TODO: List keywords and load content. mcbShelf.close()

像這種命令行程序, 一般應該在代碼開頭的注釋裡面說明程序的使用方法(1). 這樣一來以後你就算忘了程序是怎麼用, 只要過來看一下注釋就能想起來了. (2)這裡是導入需要的模塊, shelve, pyperclip之前都已經用過了, 讀取命令行參數需要用到sys. Shelve模塊的好處在於方便存儲數據. 用戶在使用save參數存儲剪貼板數據的時候, 程序可以把數據放進shelf文件; 而用戶需要讀取對應數據的時候, 程序又可以從shelf文件獲取數據, 貼回剪貼板. (3)將shelf文件文件名設置為mcb.

第2步: 用關鍵字保存剪貼板內容

我們的程序需要應對三種不同的情況:(1)存儲數據, (2)獲得數據或者(3)列出所有關鍵字. 讓我們對這些情況逐個解決. 首先是第一種情況, 代碼如下:

#! python3 # mcb.pyw - Saves and loads pieces of text to the clipboard. --snip-- # Save clipboard content.? if len(sys.argv) == 3 and sys.argv[1].lower() == save:? mcbShelf[sys.argv[2]] = pyperclip.paste() elif len(sys.argv) == 2:? # TODO: List keywords and load content. mcbShelf.close()

如果命令行第一個參數(第一個參數在sys.argv的index就是1)是save的話(1), 第二個參數就被用作當前剪貼板內容的關鍵字. 關鍵字會被用作mcbShelf里的key, 對應的value就是當前剪貼板的內容(2).


推薦閱讀:

TAG:Python | Python入門 | 辦公自動化 |