<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            10.2. 標準輸入、輸出和錯誤

            UNIX 用戶已經對標準輸入、標準輸出和標準錯誤的概念非常熟悉了。這一節是為其他不熟悉的人準備的。

            標準輸入和標準錯誤 (通常縮寫為 stdoutstderr) 是內建在每一個 UNIX 系統中的管道。當你 print 某些東西時,結果前往 stdout 管道;當你的程序崩潰并打印出調試信息 (例如 Python 中的 traceback (錯誤跟蹤)) 的時候,信息前往 stderr 管道。通常這兩個管道只與你正在工作的終端窗口相聯,所以當一個程序打印時,你可以看到輸出,而當一個程序崩潰時,你可以看到調試信息。(如果你正在一個基于窗口的 Python IDE 上工作,stdoutstderr 缺省為你的“交互窗口”。)

            例 10.8. stdoutstderr 介紹

            >>> for i in range(3):
            ...     print 'Dive in'             1
            Dive in
            Dive in
            Dive in
            >>> import sys
            >>> for i in range(3):
            ...     sys.stdout.write('Dive in') 2
            Dive inDive inDive in
            >>> for i in range(3):
            ...     sys.stderr.write('Dive in') 3
            Dive inDive inDive in
            1 正如在例 6.9 “簡單計數”中看到的,你可以使用 Python 內置的 range 函數來構造簡單的計數循環,即重復某物一定的次數。
            2 stdout 是一個類文件對象;調用它的 write 函數可以打印出你給定的任何字符串。實際上,這就是 print 函數真正做的事情;它在你打印的字符串后面加上一個硬回車,然后調用 sys.stdout.write 函數。
            3 在最簡單的例子中,stdoutstderr 把它們的輸出發送到相同的地方:Python IDE (如果你在一個 IDE 中的話),或者終端 (如果你從命令行運行 Python 的話)。和 stdout 一樣,stderr 并不為你添加硬回車;如果需要,要自己加上。

            stdoutstderr 都是類文件對象,就像在第 10.1 節 “抽象輸入源”中討論的一樣,但是它們都是只寫的。它們都沒有 read 方法,只有 write 方法。然而,它們仍然是類文件對象,因此你可以將其它任何 (類) 文件對象賦值給它們來重定向其輸出。

            例 10.9. 重定向輸出

            [you@localhost kgp]$ python stdout.py
            Dive in
            [you@localhost kgp]$ cat out.log
            This message will be logged instead of displayed

            (在 Windows 上,你要使用 type 來代替 cat 顯示文件的內容。)

            如果您還沒有下載本書附帶的樣例程序, 可以 下載本程序和其他樣例程序

            #stdout.py
            import sys
            
            print 'Dive in'                                          1
            saveout = sys.stdout                                     2
            fsock = open('out.log', 'w')                             3
            sys.stdout = fsock                                       4
            print 'This message will be logged instead of displayed' 5
            sys.stdout = saveout                                     6
            fsock.close()                                            7
            
            1 打印輸出到 IDE交互窗口” (或終端,如果從命令行運行腳本的話)。
            2 始終在重定向前保存 stdout,這樣的話之后你還可以將其設回正常。
            3 打開一個新文件用于寫入。如果文件不存在,將會被創建。如果文件存在,將被覆蓋。
            4 所有后續的輸出都會被重定向到剛才打開的新文件上。
            5 這樣只會將輸出結果“打印”到日志文件中;在 IDE 窗口中或在屏幕上不會看到輸出結果。
            6 在我們將 stdout 搞亂之前,讓我們把它設回原來的方式。
            7 關閉日志文件。

            重定向 stderr 以完全相同的方式進行,只要把 sys.stdout 改為 sys.stderr

            例 10.10. 重定向錯誤信息

            [you@localhost kgp]$ python stderr.py
            [you@localhost kgp]$ cat error.log
            Traceback (most recent line last):
              File "stderr.py", line 5, in ?
                raise Exception, 'this error will be logged'
            Exception: this error will be logged

            如果您還沒有下載本書附帶的樣例程序, 可以 下載本程序和其他樣例程序

            #stderr.py
            import sys
            
            fsock = open('error.log', 'w')               1
            sys.stderr = fsock                           2
            raise Exception, 'this error will be logged' 3 4
            
            1 打開你要存儲調試信息的日志文件。
            2 將新打開的日志文件的文件對象賦值給 stderr 以重定向標準錯誤。
            3 引發一個異常。從屏幕輸出上可以注意到這個行為沒有 在屏幕上打印出任何東西。所有正常的跟蹤信息已經寫進 error.log
            4 還要注意你既沒有顯式關閉日志文件,也沒有將 stderr 設回最初的值。這樣挺好,因為一旦程序崩潰 (由于引發的異常),Python 將替我們清理并關閉文件,因此永遠不恢復 stderr 不會造成什么影響。然而對于 stdout,恢復初始值相對更為重要――你可能會在后面再次操作標準輸出。

            向標準錯誤寫入錯誤信息是很常見的,所以有一種較快的語法可以立刻導出信息。

            例 10.11. 打印到 stderr

            >>> print 'entering function'
            entering function
            >>> import sys
            >>> print >> sys.stderr, 'entering function' 1
            entering function
            
            1 print 語句的快捷語法可以用于寫入任何打開的文件 (或者是類文件對象)。在這里,你可以將單個 print 語句重定向到 stderr 而且不用影響后面的 print 語句。

            另一方面,標準輸入是一個只讀文件對象,它表示從前一個程序到這個程序的數據流。這個對于老的 Mac OS 用戶和 Windows 用戶可能不太容易理解,除非你受到過 MS-DOS 命令行的影響。在 MS-DOS 命令行中,你可以使用一行指令構造一個命令的鏈,使得一個程序的輸出就可以成為下一個程序的輸入。第一個程序只是簡單地輸出到標準輸出上 (程序本身沒有做任何特別的重定向,只是執行了普通的 print 語句等),然后,下一個程序從標準輸入中讀取,操作系統就把一個程序的輸出連接到一個程序的輸入。

            例 10.12. 鏈接命令

            [you@localhost kgp]$ python kgp.py -g binary.xml         1
            01100111
            [you@localhost kgp]$ cat binary.xml                      2
            <?xml version="1.0"?>
            <!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
            <grammar>
            <ref id="bit">
              <p>0</p>
              <p>1</p>
            </ref>
            <ref id="byte">
              <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
            <xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
            </ref>
            </grammar>
            [you@localhost kgp]$ cat binary.xml | python kgp.py -g - 3 4
            10110001
            1 正如你在第 9.1 節 “概覽”中看到的,該命令將只打印一個隨機的八位字符串,其中只有 0 或者 1
            2 該處只是簡單地打印出整個 binary.xml 文檔的內容。(Windows 用戶應該用 type 代替 cat。)
            3 該處打印 binary.xml 的內容,但是“|”字符,稱為“管道”符,說明內容不會打印到屏幕上;它們會成為下一個命令的標準輸入,在這個例子中是你調用的 Python 腳本。
            4 為了不用指定一個文件 (例如 binary.xml),你需要指定“-”,它會使得你的腳本從標準輸入載入腳本,而不是從磁盤上的特定文件。 (下一個例子更多地說明了這是如何實現的)。所以效果和第一種語法是一樣的,在那里你要直接指定語法文件,但是想想這里的擴展性。讓我們把 cat binary.xml 換成別的什么東西――例如運行一個腳本動態生成語法――然后通過管道將它導入你的腳本。它可以來源于任何地方:數據庫,或者是生成語法的元腳本,或者其他。你根本不需要修改你的 kgp.py 腳本就可以并入這個功能。你要做的僅僅是從標準輸入取得一個語法文件,然后你就可以將其他的邏輯分離出來,放到另一程序中去了。

            那么腳本是如何“知道”在語法文件是“-”時從標準輸入讀取? 其實不神奇;它只是代碼。

            例 10.13. 在 kgp.py 中從標準輸入讀取

            
            def openAnything(source):
                if source == "-":    1
                    import sys
                    return sys.stdin
            
                # try to open with urllib (if source is http, ftp, or file URL)
                import urllib
                try:
            
            [... snip ...]
            1 這是 toolbox.py 中的 openAnything 函數,以前在第 10.1 節 “抽象輸入源”中你已經檢視過了。所有你要做的就是在函數的開始加入 3 行代碼來檢測源是否是“-”;如果是,返回 sys.stdin。就這么簡單!記住,stdin 是一個擁有 read 方法的類文件對象,所以其它的代碼 (在 kgp.py 中,在那里你調用了 openAnything) 一點都不需要改動。
            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线