sys — 系統相關的參數以及函式
This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter. It is always available.
官方介紹文件:29.1 sys – System-specific parameters and functions
sys
是一個極其強大的 Python 標準函式庫,大家常常忽略他的存在,但是當要做到一些奇淫技巧的時候,就會需要使用 sys 來達成。
01. sys.argv – dealing with command line arguments
sys.argv 用來表示從 command line 傳入的參數,sys.argv[0] 代表著程式的名稱。如果你對 C 熟悉的話,就會想起這個東西 int main(int argc, char *argv[])
,sys.argv 就相當於char *argv[]
。
常見的使用場景:當你需要快速的做出與 command line 互動的程式時,就會需要用到 sys.argv。例如說,我想要做一個輸入股票代號,就能幫我查詢股價的程式時,就可以使用 sys.argv 來取得自 command line 傳入的參數:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ cat stock.py #! /usr/bin/python3 import sys import twstock if __name__ == ‘__main__’: if len(sys.argv) == 2: s = twstock.Stock(sys.argv[1]) print(s.price[–5:]) $ ./stock.py 2330 [214.5, 215.5, 214.0, 214.5, 214.0] |
如果要更為複雜的操作 command line 參數的話,建議使用 argparse。
02. sys.platform
sys.platform 常用來判斷是否要執行平台相關的程式碼,通常這樣用:
1 2 3 4 5 6 7 8 |
if sys.platform.startswith(‘win32’): # Do Windows stuff elif sys.platform.startswith(‘darwin’): # Do MacOS stuff elif sys.platform.startswith(‘linux’): # Do Linux stuff else: # Fallback |
在 Unix 平台上 (除了 Linux 以外),sys.platform 的值會是 uname -s
的第一部份,例如說 'sunos5'
或 'freebsd8'
。Linux 是 'linux'
、Windows 是 'win32'
、Cygwin 是 'cygwin'
、Mac OS X 是 'darwin'
。
03. sys.version_info
sys.version_info 提供一組 tuple (major, minor, micro, releaselevel, serial) 來表示當前 Python 的版本。舉例而言,如果你從 CPython 原始碼編譯整個 CPython 的話,從 sys.version_info 會得到這樣的 tuple:
1 |
sys.version_info(major=3, minor=7, micro=0, releaselevel=‘alpha’, serial=0) |
通常會用在需要判斷 Python 2 或是 Python 3 的時候:
1 2 3 4 |
import sys PY2 = sys.version_info.major == 2 PY3 = sys.version_info.major == 3 |
04. sys.path
sys.path 是一個 list of strings,用來表示 import search path。
1 2 3 |
>>> import sys >>> sys.path [”, ‘/usr/lib/python36.zip’, ‘/usr/lib/python3.6’, ‘/usr/lib/python3.6/lib-dynload’, ‘/home/grd/.local/lib/python3.6/site-packages’, ‘/usr/lib/python3.6/site-packages’, ‘/usr/lib/python3.6/site-packages/cosmic_ray-1.0.0a1-py3.6.egg’, ‘/usr/lib/python3.6/site-packages/nose-1.3.7-py3.6.egg’, ‘/usr/lib/python3.6/site-packages/lice-0.4-py3.6.egg’, ‘/usr/lib/python3.6/site-packages/howdoi-1.1.9-py3.6.egg’, ‘/usr/lib/python3.6/site-packages/Cherry_Picker-0.0.0-py3.6.egg’, ‘/usr/lib/python3.6/site-packages/twstock-0.1-py3.6.egg’, ‘/usr/lib/python3.6/site-packages/perf-1.5-py3.6.egg’] |
通常不會用到,但是當有需要的時候會很好用。例如說,要避免新手在自己的資料夾下面創立一個與標準函式庫相同名稱的 .py 檔案,然後 import 成該檔案的時候,可以先把 sys.path 中的 ''
移除來避免這樣的狀況發生。
06. sys.stdin, sys.stdout, sys.stderr
3 個 standard data stream 如同普通的 File object,你可以對它們做任何事情。
例如說把 sys.stdout 關閉:
1 2 3 4 5 |
>>> sys.stdout.close() >>> print(‘no way’) Traceback (most recent call last): File “<stdin>”, line 1, in <module> ValueError: I/O operation on closed file. |
或是替換 sys.stdout 好在 Windows 上支援 unicode 輸出:
1 2 3 4 5 |
>>> import sys >>> import io >>> sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding=‘utf-8’) >>> print(‘萬國碼’) ‘萬國碼’ |
相對應的預設資料流,被保存在 sys.__stdin__
、sys.__stdout___
、sys.__stderr__
之中所以不用擔心毀掉整個資料流,輕鬆回復即可:
1 2 |
>>> sys.stdout = WhatBadThingYouDo() >>> sys.stdout = sys.__stdout__ |
07. sys.displayhook(value)
sys.displayhook(value) ,從名稱很明顯可以知道 displayhook 會在顯示東西時被觸發的 hook。CPython 所預設的 displayhook 可以使用 sys.__displayhook__
取得,所以不用擔心如果變更 displayhook 後沒有辦法回復。預設的 displayhook 基本上做了這件事情:1. 將 obj 以 repr(obj) 的方式印出 2. 將 obj 存入 BUILTINS._
當中。
使用情境可以是這樣,如果 obj 是 dict,我要改用 pprint 印出:
1 2 3 4 5 6 7 8 9 10 11 |
import sys import pprint def dict_displayhook(obj): if isinstance(obj, dict): pprint.pprint(obj) __builtins__._ = obj else: sys.__displayhook__(obj) sys.displayhook = dict_displayhook |
08. sys.exceptionhook(type, value, traceback)
sys.exceptionhook(type, value, traceback),當程式觸發 exception 的時候,就會使用 exceptionhook 來 handle 這個 exception。與 displayhook 相同,預設使用的 exceptionhook 會存放 sys.__exceptionhook__
,所以不用擔心無法復原。預設的動作是將 traceback 以及 exception 輸出到 sys.stderr
。
可以這樣使用 – raises-stackoverflow:遇到錯誤時不只有印出錯誤訊息,還會順便打開 browser 連到堆疊溢出來查詢如何解決問題。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import sys import webbrowser STACKOVERFLOW_URL = ‘https://stackoverflow.com/search?tab=votes&{qs}’ def raiser(etype, value, tb): error_msg = ‘{etype}: {value}’.format(etype=etype.__name__, value=value) webbrowser.open(STACKOVERFLOW_URL.format( qs=urlencode({‘q’: ‘[python] ‘ + error_msg})), new=2) # new=2 open in new tab sys.__excepthook__(etype, value, tb) # Globaly replace sys.excepthook to raiser sys.excepthook = raiser |
09. sys.setrecursionlimit(limit)
sys.setrecursionlimit(limit) 用來設定遞迴最多能到幾層 (實際上是限制 interpreter stack 的 maximum depth 到 limit)。如果遞迴超出 limit,會丟出 RecursionError。如果在遞迴中設定低於目前層數的 limit,也會丟出 RecursionError。
有 set 就有 get,可以使用 sys.getrecursionlimit()
取得目前設定的 limit。
10. sys.setswitchinterval(interval)
sys.setswitchinterval(interval) 用來設定 interpreter 多少時間會切換 thread。這跟 Python GIL 有關,在 Python 2 時,採用每 1000 個 byte code 會切換一次 thread,Python 3 採用時間切換。預設的時間為 0.005 秒。
11. sys.settrace(tracefunc)
sys.settrace(tracefunc) 用來設定 Python 的追蹤函式,讓你可以做出 debugger。pdb 以及 bdb 就是是基於這個 protocal 做成的。意思就是透過 tracefunc,我們可以在特定狀況下暫停 (應該說相關的參數會被傳入 tracefunc),然後操作這些參數。
tracefunc 需要有 3 個參數:frame, event, arg。 frame 表示目前 stack 上的 frame。event 表示型態:'call'
、'line'
、'return'
、'exception'
、'c_call'
、'c_return'
、’c_exception'
。而 arg 代表相對應 event 所需要的參數。
詳細使用方式請參考 Lib/pdb.py。
p.s. 實際上這東西不會理會'c_call'
、'c_return'
、’c_exception'
。
12. sys.setprofile(profilefunc)
sys.setprofile(profilefunc) 跟前一個函式很相似,但是用於 profiler。不過他只會回應 'call'
以及 ‘return'
event 而已。
詳細使用方式請參考 Lib/profile.py。
Leave a Reply