# 練習20. 函數和文件
回憶一下函數的要點,然后一邊做這節練習,一邊注意一下函數和文件是如何在一起協作發揮作用的。
~~~
from sys import argv
script, input_file = argv
def print_all(f):
print f.read()
def rewind(f):
f.seek(0)
def print_a_line(line_count, f):
print line_count, f.readline()
current_file = open(input_file)
print "First let's print the whole file:\n"
print_all(current_file)
print "Now let's rewind, kind of like a tape."
rewind(current_file)
print "Let's print three lines:"
current_line = 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
~~~
特別注意一下,每次運行`print_a_line`時,我們是怎樣傳遞當前的行號信息的。
## 你看到的結果
~~~
$ python ex20.py test.txt
First let's print the whole file:
This is line 1
This is line 2
This is line 3
Now let's rewind, kind of like a tape.
Let's print three lines:
1 This is line 1
2 This is line 2
3 This is line 3
~~~
## 附加題
> 1. 通讀腳本,在每行之前加上注解,以理解腳本里發生的事情。
> 1. 每次`print_a_line`運行時,都傳遞了一個叫`current_line`的變量。在每次調用函數時,打印出`current_line`的值,跟蹤一下它在`print_a_line`中是怎樣變成`line_count`的。
> 1. 找出腳本中每一個用到函數的地方。檢查`def`一行,確認參數沒有用錯。
> 1. 上網研究一下`file`中的`seek`函數是做什么用的。試著運行`pydoc file`看看能不能學到更多。
> 1. 研究一下`+=`這個簡寫操作符的作用,寫一個腳本,把這個操作符用在里邊試一下。
## 常見問題
### Q:函數`print_all`中的`f`是什么?
> `f` 就是一個變量,就好像在練習18中其他的變量一樣,只不過這次它代表了一個文件。 Python中的文件就好像老舊的磁帶驅動器,或者是像現在的DVD播放器。它有一個 "磁頭",你可以在文件中"查找"到這個磁頭的位置,并且從那個位置開始運行。你每執行一次 `f.seek(0)`,就靠近文件的開頭一點。每執行一次`f.readline()`你就從文件中讀取一行內容,并且把“磁頭”移動到文件末尾,換行符`\n`的后面。繼續學習本書,你會看到更多的解釋。
### Q: 文件中為什么有3個空行?
> 函數 `readline()` 返回一行以`\n`結尾的文件內容, 在你調用print函數的最后增加一個逗號',',用來避免為每一行添加兩個換行符`\n`。
### Q:為什么`seek(0)`方法沒有把`current_line`的值修改為0?
> 首先,`seek()`方法是按字節而不是按行為處理單元的。代碼`seek(0)`重新定位在文件的第0位(第一個字節處)。再次,`current_line`是一個變量,在文件中沒有真正的意義可言。我們是在手動的增加它的值。
### Q:`+=`是什么?
> 你應該知道在英語里我們可以簡寫 "it is" 為 "it's",簡寫 "you are" 為 "you're"。在英語里我們把這種寫法稱為縮寫,同樣的,`+=`是 `=`和 `+`兩個操作符的縮寫. 比如`x = x + y`可以縮寫為`x += y`.
### Q:`readline()`怎么知道每一行的分界在哪里?
> `readline()`內部代碼是掃描文件的每一個字節,直到找到一個`\n`字符代碼,然后停止閱讀,并返回到此之前獲得的所有內容。代碼中f的責任是在每次調用`readline()`之后,維護“磁頭”在文件中的位置,以保證繼續讀后面的每一行。
- 序言
- 前言
- 簡介
- 0:安裝和準備
- 1:第一個程序
- 2:注釋和“#”井號
- 3:數字和數學計算
- 4:變量和命名
- 5:更多的變量和打印
- 6:字符串和文本
- 7:更多的打印(輸出)
- 8:打印, 打印
- 9:打印, 打印, 打印
- 10:那是什么?
- 11:提問
- 12:提示別人
- 13:參數, 解包, 變量
- 14:提示和傳遞
- 15:讀文件
- 16:讀寫文件
- 17:更多文件操作
- 18:命名, 變量, 代碼, 函數
- 19:函數和變量
- 20:函數和文件
- 21:函數的返回值
- 22:到目前為止你學到了什么?
- 23:閱讀代碼
- 24:更多的練習
- 25:更多更多的練習
- 26:恭喜你,可以進行一次考試了
- 27:記住邏輯
- 28:布爾表達式
- 29:IF 語句
- 30:Else 和 If
- 31:做出決定
- 32:循環和列表
- 33:while循環
- 34:訪問列表元素
- 35:分支和函數
- 36:設計和調試
- 37:復習符號
- 38:列表操作
- 39:字典,可愛的字典
- 40:模塊, 類和對象
- 41:學會說面向對象
- 42:對象、類、以及從屬關系
- 43:基本的面向對象的分析和設計
- 44:繼承Vs.包含
- 45:你來制作一個游戲
- 46:項目骨架
- 47:自動化測試
- 48:更復雜的用戶輸入
- 49:寫代碼語句
- 50:你的第一個網站
- 51:從瀏覽器獲取輸入
- 52:開始你的web游戲
- 來自老程序員的建議
- 下一步
- 附錄A:命令行教程
- 簡介
- 安裝和準備
- 路徑, 文件夾, 名錄 (pwd)
- 如果你迷路了
- 創建一個路徑 (mkdir)
- 改變當前路徑 (cd)
- 列出當前路徑 (ls)
- 刪除路徑 (rmdir)
- 目錄切換(pushd, popd)
- 生成一個空文件(Touch, New-Item)
- 復制文件 (cp)
- 移動文件 (mv)
- 查看文件 (less, MORE)
- 輸出文件 (cat)
- 刪除文件 (rm)
- 退出命令行 (exit)
- 下一步