==sys 模塊==
``sys`` 模塊提供了許多函數和變量來處理 Python 運行時環境的不同部分.
=== 處理命令行參數===
在解釋器啟動后, ``argv`` 列表包含了傳遞給腳本的所有參數, 如 [Example 1-66 #eg-1-66] 所示.
列表的第一個元素為腳本自身的名稱.
====Example 1-66. 使用sys模塊獲得腳本的參數====[eg-1-66]
```
File: sys-argv-example-1.py
import sys
print "script name is", sys.argv[0]
if len(sys.argv) > 1:
print "there are", len(sys.argv)-1, "arguments:"
for arg in sys.argv[1:]:
print arg
else:
print "there are no arguments!"
*B*script name is sys-argv-example-1.py
there are no arguments!*b*
```
如果是從標准輸入讀入腳本 (比如 "``python < sys-argv-example-1.py``"),
腳本的名稱將被設置為空串. 如果把腳本作為字符串傳遞給python (使用 ``-c`` 選項),
腳本名會被設置為 "-c".
=== 處理模塊 ===
``path`` 列表是一個由目錄名構成的列表, Python 從中查找擴展模塊( Python 源模塊, 編譯模塊,或者二進制擴展).
啟動 Python 時,這個列表從根據內建規則, PYTHONPATH 環境變量的內容, 以及注冊表( Windows 系統)等進行初始化.
由於它只是一個普通的列表, 你可以在程序中對它進行操作, 如 [Example 1-67 #eg-1-67] 所示.
====Example 1-67. 使用sys模塊操作模塊搜索路徑====[eg-1-67]
```
File: sys-path-example-1.py
import sys
print "path has", len(sys.path), "members"
# add the sample directory to the path
sys.path.insert(0, "samples")
import sample
# nuke the path
sys.path = []
import random # oops!
*B*path has 7 members
this is the sample module!
Traceback (innermost last):
File "sys-path-example-1.py", line 11, in ?
import random # oops!
ImportError: No module named random*b*
```
``builtin_module_names`` 列表包含 Python 解釋器中所有內建模塊的名稱, [Example 1-68 #eg-1-68]
給出了它的樣例代碼.
====Example 1-68. 使用sys模塊查找內建模塊====[eg-1-68]
```
File: sys-builtin-module-names-example-1.py
import sys
def dump(module):
print module, "=>",
if module in sys.builtin_module_names:
print "<BUILTIN>"
else:
module = _ _import_ _(module)
print module._ _file_ _
dump("os")
dump("sys")
dump("string")
dump("strop")
dump("zlib")
*B*os => C:\python\lib\os.pyc
sys => <BUILTIN>
string => C:\python\lib\string.pyc
strop => <BUILTIN>
zlib => C:\python\zlib.pyd*b*
```
``modules`` 字典包含所有加載的模塊. ``import`` 語句在從磁盤導入內容之前會先檢查這個字典.
正如你在 [Example 1-69 #eg-1-69] 中所見到的, Python 在處理你的腳本之前就已經導入了很多模塊.
====Example 1-69. 使用sys模塊查找已導入的模塊====[eg-1-69]
```
File: sys-modules-example-1.py
import sys
print sys.modules.keys()
*B*['os.path', 'os', 'exceptions', '_ _main_ _', 'ntpath', 'strop', 'nt',
'sys', '_ _builtin_ _', 'site', 'signal', 'UserDict', 'string', 'stat']*b*
```
=== 處理引用記數===
``getrefcount`` 函數 (如 [Example 1-70 #eg-1-70] 所示) 返回給定對象的引用記數 -
也就是這個對象使用次數. Python 會跟蹤這個值, 當它減少為0的時候, 就銷毀這個對象.
====Example 1-70. 使用sys模塊獲得引用記數====[eg-1-70]
```
File: sys-getrefcount-example-1.py
import sys
variable = 1234
print sys.getrefcount(0)
print sys.getrefcount(variable)
print sys.getrefcount(None)
*B*50
3
192*b*
```
注意這個值總是比實際的數量大, 因為該函數本身在確定這個值的時候依賴這個對象.
== 檢查主機平台===
[Example 1-71 #eg-1-71] 展示了 ``platform`` 變量, 它包含主機平台的名稱.
====Example 1-71. 使用sys模塊獲得當前平台====[eg-1-71]
```
File: sys-platform-example-1.py
import sys
#
# emulate "import os.path" (sort of)...
if sys.platform == "win32":
import ntpath
pathmodule = ntpath
elif sys.platform == "mac":
import macpath
pathmodule = macpath
else:
# assume it's a posix platform
import posixpath
pathmodule = posixpath
print pathmodule
```
典型的平台有Windows 9X/NT(顯示為 ``win32`` ), 以及 Macintosh(顯示為 ``mac`` ) .
對於 Unix 系統而言, platform 通常來自 "``uname -r``" 命令的輸出, 例如 ``irix6`` , ``linux2`` ,
或者 ``sunos5`` (Solaris).
=== 跟蹤程序===
``setprofiler`` 函數允許你配置一個分析函數(profiling function).
這個函數會在每次調用某個函數或方法時被調用(明確或隱含的),
或是遇到異常的時候被調用. 讓我們看看 [Example 1-72 #eg-1-72] 的代碼.
====Example 1-72. 使用sys模塊配置分析函數====[eg-1-72]
```
File: sys-setprofiler-example-1.py
import sys
def test(n):
j = 0
for i in range(n):
j = j + i
return n
def profiler(frame, event, arg):
print event, frame.f_code.co_name, frame.f_lineno, "->", arg
# profiler is activated on the next call, return, or exception
# 分析函數將在下次函數調用, 返回, 或異常時激活
sys.setprofile(profiler)
# profile this function call
# 分析這次函數調用
test(1)
# disable profiler
# 禁用分析函數
sys.setprofile(None)
# don't profile this call
# 不會分析這次函數調用
test(2)
*B*call test 3 -> None
return test 7 -> 1*b*
```
基於該函數, ``profile`` 模塊提供了一個完整的分析器框架.
[Example 1-73 #eg-1-73] 中的 ``settrace`` 函數與此類似,
但是 ``trace`` 函數會在解釋器每執行到新的一行時被調用.
====Example 1-73. 使用sys模塊配置單步跟蹤函數====[eg-1-73]
```
File: sys-settrace-example-1.py
import sys
def test(n):
j = 0
for i in range(n):
j = j + i
return n
def tracer(frame, event, arg):
print event, frame.f_code.co_name, frame.f_lineno, "->", arg
return tracer
# tracer is activated on the next call, return, or exception
# 跟蹤器將在下次函數調用, 返回, 或異常時激活
sys.settrace(tracer)
# trace this function call
# 跟蹤這次函數調用
test(1)
# disable tracing
# 禁用跟蹤器
sys.settrace(None)
# don't trace this call
# 不會跟蹤這次函數調用
test(2)
*B*call test 3 -> None
line test 3 -> None
line test 4 -> None
line test 5 -> None
line test 5 -> None
line test 6 -> None
line test 5 -> None
line test 7 -> None
return test 7 -> 1*b*
```
基於該函數提供的跟蹤功能, ``pdb`` 模塊提供了完整的調試( debug )框架.
=== 處理標准輸出/輸入 ===
``stdin`` , ``stdout`` , 以及 ``stderr`` 變量包含與標准 I/O 流對應的流對象.
如果需要更好地控制輸出,而 ``print`` 不能滿足你的要求, 它們就是你所需要的.
你也可以 //替換// 它們, 這時候你就可以重定向輸出和輸入到其它設備( device ),
或者以非標准的方式處理它們. 如 [Example 1-74 #eg-1-74] 所示.
====Example 1-74. 使用sys重定向輸出====[eg-1-74]
```
File: sys-stdout-example-1.py
import sys
import string
class Redirect:
def _ _init_ _(self, stdout):
self.stdout = stdout
def write(self, s):
self.stdout.write(string.lower(s))
# redirect standard output (including the print statement)
# 重定向標准輸出(包括print語句)
old_stdout = sys.stdout
sys.stdout = Redirect(sys.stdout)
print "HEJA SVERIGE",
print "FRISKT HUM\303\226R"
# restore standard output
# 恢復標准輸出
sys.stdout = old_stdout
print "M\303\205\303\205\303\205\303\205L!"
*B*heja sverige friskt hum\303\266r
M\303\205\303\205\303\205\303\205L!*b*
```
要重定向輸出只要創建一個對象, 並實現它的 ``write`` 方法.
(除非 C 類型的實例外:Python 使用一個叫做 ``softspace`` 的整數屬性來控制輸出中的空白.
如果沒有這個屬性, Python 將把這個屬性附加到這個對象上. 你不需要在使用 Python 對象時擔心,
但是在重定向到一個 C 類型時, 你應該確保該類型支持 ``softspace`` 屬性.)
=== 退出程序===
執行至主程序的末尾時,解釋器會自動退出. 但是如果需要中途退出程序, 你可以調用 ``sys.exit`` 函數,
它帶有一個可選的整數參數返回給調用它的程序. [Example 1-75 #eg-1-75] 給出了范例.
====Example 1-75. 使用sys模塊退出程序====[eg-1-75]
```
File: sys-exit-example-1.py
import sys
print "hello"
sys.exit(1)
print "there"
*B*hello*b*
```
注意 ``sys.exit`` 並不是立即退出. 而是引發一個 //SystemExit// 異常.
這意味着你可以在主程序中捕獲對 ``sys.exit`` 的調用, 如 [Example 1-76 #eg-1-76] 所示.
====Example 1-76. 捕獲sys.exit調用====[eg-1-76]
```
File: sys-exit-example-2.py
import sys
print "hello"
try:
sys.exit(1)
except SystemExit:
pass
print "there"
*B*hello
there*b*
```
如果准備在退出前自己清理一些東西(比如刪除臨時文件), 你可以配置一個
"退出處理函數"(exit handler), 它將在程序退出的時候自動被調用. 如 [Example 1-77 #eg-1-77] 所示.
====Example 1-77. 另一種捕獲sys.exit調用的方法====[eg-1-77]
```
File: sys-exitfunc-example-1.py
import sys
def exitfunc():
print "world"
sys.exitfunc = exitfunc
print "hello"
sys.exit(1)
print "there" # never printed # 不會被 print
*B*hello
world*b*
```
在 Python 2.0 以后, 你可以使用 ``atexit`` 模塊來注冊多個退出處理函數.