在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 操作系統(tǒng)
附錄
進程通信
操作系統(tǒng)
迭代器
模塊
描述符
裝飾器
第三部分 擴展庫
內置類型
數(shù)據(jù)存儲
數(shù)據(jù)類型
基本環(huán)境
文件與目錄
異常
程序框架
數(shù)學運算
函數(shù)
元類
字符串
表達式

操作系統(tǒng)

time

Unix-Like 系統(tǒng)使用自基準點以來消逝的秒數(shù)來表達絕對時間。

  • 絕對時間: 某個絕對精確的時間值。如 2010-11-1 13:48:05 。
  • 相對時間: 相對于某個時間的前后差。如 5分鐘以前。
  • epoch: 基準點。1970-01-01 00:00:00 UTC。
  • UTC: 協(xié)調世界時。世界不同時區(qū)的一個基準,比如中國為 UTC+8。
  • DST: 陽光節(jié)約時 (夏時制)。好在我國已經取消了,真麻煩。

用 time() 返回自 epoch 以來的秒數(shù),gmtime()、localtime() 將其轉換為 struct_time 結構體。

>>> from time import *

>>> t = time()
>>> t
1357761634.903692

>>> gmtime(t)   # epoch -> UTC
time.struct_time(tm_year=2013, tm_mon=1, tm_mday=9, tm_hour=20, tm_min=0, tm_sec=34,
tm_wday=2, tm_yday=9, tm_isdst=0)

>>> localtime(t)   # epoch -> Local (UTC+8)
time.struct_time(tm_year=2013, tm_mon=1, tm_mday=10, tm_hour=4, tm_min=0, tm_sec=34,
tm_wday=3, tm_yday=10, tm_isdst=0)

將 struct_time 轉回 epoch。

>>> from calendar import timegm

>>> t = time()
>>> t
1357762219.162796

>>> utc = gmtime(t)  # epoch -> UTC
>>> timegm(utc)   # UTC -> epoch
1357762219

>>> local = localtime(t)  # epoch -> local
>>> mktime(local)   # local -> epoch
1357762219

與 datetime 的轉換,注意返回的是 localtime 時間。

>>> from datetime import datetime
>>> from time import time

>>> t = time()

>>> d = datetime.fromtimestamp(t)  # localtime 時間
>>> d
datetime.datetime(2013, 1, 10, 4, 20, 27, 301148)

>>> d.timetuple()
time.struct_time(tm_year=2013, tm_mon=1, tm_mday=10, tm_hour=4, tm_min=20, tm_sec=27,
tm_wday=3, tm_yday=10, tm_isdst=-1)

相關函數(shù):

ctime: 將 epoch 轉換為字符串。 asctime: 將 struct_time 轉換為字符串。

>>> t = time()

>>> ctime(t)
'Thu Jan 10 04:26:01 2013'

>>> asctime(localtime(t))
'Thu Jan 10 04:26:01 2013'

clock: 返回當前進程消耗的CPU時間 (秒)。 sleep: 暫停進程 (秒,可以是小數(shù),以便設置毫秒、微秒級暫停)。

>>> clock()
0.56022400000000006

>>> sleep(0.1)

strftime: 將 struct_time 格式化為字符串。 strptime: 將字符串格式化為 struct_time。

>>> t = time()

>>> s = strftime("%Y-%m-%d %H:%M:%S", localtime(t))
>>> s
'2013-01-10 04:27:39'

>>> strptime(s, "%Y-%m-%d %H:%M:%S")
time.struct_time(tm_year=2013, tm_mon=1, tm_mday=10, tm_hour=4, tm_min=27, tm_sec=39,
tm_wday=3, tm_yday=10, tm_isdst=-1)

timezone: 與 UTC 的時差。 tzname: 當前時區(qū)名稱。

>>> timezone / 3600
-8

>>> tzname    # 北京時間,China Standard Time
('CST', 'CST')

threading

盡管因為 GIL 的緣故,Python 多線程一直遭受種種非議。但作為多個并發(fā)執(zhí)行流程,多線程是無法完全用 "手工" 切換的協(xié)程來替代的。

Thread

創(chuàng)建 Thread 實例,傳入待執(zhí)行函數(shù)。

>>> from threading import Thread, currentThread, activeCount

>>> def test(s):
...     print "ident:", currentThread().ident
...     print "count:", activeCount()
...     print s
...

>>> Thread(target = test, args = ("Hello",)).start()
ident: 4353970176
count: 3
Hello

除了標識符,還可以線程取個名字,這有助于調試。

還可以繼承 Thread 實現(xiàn)自己的線程類。

>>> class MyThread(Thread):
...     def __init__(self, name, *args):
...         super(MyThread, self).__init__(name = name)
...         self.data = args
...
...     def run(self):
...         print self.name, self.data

>>> MyThread("abc", range(10)).start()
abc ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9],)

將線程 daemon 屬性設為 True,那么表示這是一個背景線程,進程退出時不會等待該線程結束。

調用 join() 等待線程結束,可提供超時參數(shù) (秒,浮點數(shù)設定更小粒度)。isAlive() 檢查線程狀態(tài),join() 可多次調用。

>>> from time import sleep

>>> def test():
...     print "__thread_start__"
...     sleep(10)
...     print "__thread_exit__"

>>> def run():
...     t = Thread(target = test)
...     t.start()
...     t.join(2)   // 超時
...
...     print t.isAlive() // 檢查狀態(tài)
...     t.join()   // 再次等待
...
...     print "over"

>>> run()
__thread_start__
True
__thread_exit__
over!

Lock

Lock 不支持遞歸加鎖,也就是說即便在同一線程中,也必須等待鎖釋放。通常建議改用 RLock,它會處理 "owning thread" 和 "recursion level" 狀態(tài),對于同一線程的多次請求鎖行為,只累加計數(shù)器。每次調用 release() 將遞減該計數(shù)器,直到 0 時釋放鎖,因此 acquire() 和 release() 必須要成對出現(xiàn)。

threading 中的成員大多實現(xiàn)了上下文協(xié)議,盡可能用 with 代替手工調用。

>>> lock = RLock()

>>> def show(i):
...     with lock:     // 遞歸請求鎖
...         print currentThread().name, i
...         sleep(0.1)

>>> def test():
...     with lock:     // 加鎖
...         for i in range(5):
...             show(i)

>>> for i in range(2):
...     Thread(target = test).start()

Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-2 0
Thread-2 1
Thread-2 2
Thread-2 3
Thread-2 4

Event

Event 通過通過一個內部標記來協(xié)調多線程運行。方法 wait() 阻塞線程執(zhí)行,直到標記為 True。set() 將標記設為 True,clear() 更改標記為 False。isSet() 用于判斷標記狀態(tài)。

>>> def test():
...     e = Event()
...     def test():
...         for i in range(5):
...             e.wait()
...             e.clear()
...             print i
...
...     Thread(target = test).start()
...     return e

>>> e = test()

>>> e.set()
0
>>> e.set()
1

如果不調用 clear(),那么標記一直為 True,wait() 就不會發(fā)生阻塞行為。

在實際編程中,我們通常為每個線程準備一個獨立的 Event,而不是多個線程共享,以避免未及時調用 clear() 時發(fā)生意外情況。

Condition

Condition 像 Lock 和 Event 的綜合體,除基本的鎖操作外,還提供了類似 yield 的功能。在獲取鎖以后,可以調用 wait() 臨時讓出鎖,當前線程被阻塞,直到 notify() 發(fā)送通知后再次請求鎖來恢復執(zhí)行。將 wait 當做 yield,那么 notify 就是 send。

可以將已有的鎖對象傳給 Condition。

>>> def t1():
...     with cond:
...         for i in range(5):
...             print currentThread().name, i
...             sleep(0.1)
...             if i == 3: cond.wait()

>>> def t2():
...     with cond:
...         for i in range(5):
...             print currentThread().name, i
...             sleep(0.1)
...         cond.notify()

>>> Thread(target = t1).start(); Thread(target = t2).start()
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3   // 讓出鎖
Thread-2 0
Thread-2 1
Thread-2 2
Thread-2 3
Thread-2 4
Thread-1 4   // 重新獲取鎖,繼續(xù)執(zhí)行。

只有獲取鎖的線程才能調用 wait() 和 notify(),因此必須在鎖釋放前調用。

當 wait() 釋放鎖后,其他線程也可進入 wait 狀態(tài)。notifyAll() 激活所有等待線程,讓它們去搶鎖然后完成后續(xù)執(zhí)行。

>>> def test():
...     with cond:
...         for i in range(5):
...         print currentThread().name, i
...         sleep(0.1)
...         if i == 2: cond.wait()

>>> Thread(target = t1).start(); Thread(target = t1).start()
Thread-1 0
Thread-1 1
Thread-1 2     // Thread-1: 等待
Thread-2 0
Thread-2 1
Thread-2 2     // Thread-2: 等待

>>> with cond: cond.notifyAll()  // 通知所有 cond.wait 線程。
Thread-2 3     // Thread-1 和 Thread-2 再次搶鎖以完成后續(xù)執(zhí)行,
Thread-2 4     // 至于誰先搶到,就不好說了。
Thread-1 3
Thread-1 4

Semaphore

Semaphore 通過一個計數(shù)器來限制可同時運行的線程數(shù)量。計數(shù)器表示還可以運行的線程數(shù)量,acquire() 遞減計數(shù)器,release() 則是增加計數(shù)器。

>>> sem = Semaphore(2)

>>> def test():
...     with sem:
...         for i in range(5):
...             print currentThread().name, i
...             sleep(0.1)

>>> for i in range(3):
...     Thread(target = test).start()

Thread-1 0   // 1 和 2 同時執(zhí)行。因為計數(shù)器為 0,所以 3 被阻塞。
Thread-2 0
Thread-1 1
Thread-2 1
Thread-1 2
Thread-2 2
Thread-1 3
Thread-2 3
Thread-1 4
Thread-2 4
Thread-3 0   // 1 和 2 釋放信號量,3 開始執(zhí)行。
Thread-3 1
Thread-3 2
Thread-3 3
Thread-3 4

Timer

用一個獨立線程在 n 秒后執(zhí)行某個函數(shù)。如定時器尚未執(zhí)行,可用 cancel() 取消,定時器僅執(zhí)行一次。

>>> def test():
...     print datetime.datetime.now()

>>> Timer(2, test).start()
2013-03-26 11:06:19.840455

Local

TLS (thread-local storage) 為線程提供獨立的存儲空間。

>>> data = local()

>>> def test(fn, x):
...     data.x = x
...     for i in range(5):
...         data.x = fn(data.x)
...         print currentThread().name, data.x
...         sleep(0.1)

>>> t1 = (lambda x: x + 1, 0)
>>> t2 = (lambda x: x + "a", "a")

>>> for d in (t1, t2):
...     Thread(target = test, args = d).start()

Thread-1 1
Thread-2 aa
Thread-2 aaa
Thread-1 2
Thread-2 aaaa
Thread-1 3
Thread-2 aaaaa
Thread-1 4
Thread-1 5
Thread-2 aaaaaa

multiprocessing

看上去和 threading 類似,區(qū)別在于用進程代替線程。這是規(guī)避 GIL,實現(xiàn)多核并發(fā)的常用方法。

Process

創(chuàng)建子進程執(zhí)行指定函數(shù)。

from multiprocessing import Process, current_process

def test(*args, **kwargs):
    p = current_process()
    print p.name, p.pid
    print args
    print kwargs

if __name__ == "__main__":
    p = Process(target=test, args=(1, 2), kwargs = {"a": "hello"}, name = "TEST")
    p.start()
    p.join()

輸出:

TEST, 2570
(1, 2)
{'a': 'hello'}

方法 start() 創(chuàng)建子進程,然后在新進程中通過 run() 執(zhí)行目標函數(shù)。構建參數(shù) args、kwargs 會傳遞給目標函數(shù)。在父進程中用 join() 等待并獲取子進程退出狀態(tài),否則會留下僵尸進程,除非父進程先終止。

從下例輸出結果,可以看到 init() 在父進程執(zhí)行,但 run() 已經是子進程了。

class MyProcess(Process):
    def __init__(self):
        print "init:", os.getpid()
        super(MyProcess, self).__init__()

    def run(self):
        print "run:", os.getpid()

if __name__ == "__main__":
    print "parent:", os.getpid()
    p = MyProcess()
    p.start()
    p.join()

輸出:

parent: 12093
init: 12093
run: 12094

子進程不會調用退出函數(shù),而且只有后臺 (daemon) 進程才可捕獲主進程退出信號,默認處理自然是終止子進程。另外,后臺進程不能創(chuàng)建新的子進程,這將導致僵尸出現(xiàn)。

from os import getpid
from time import sleep
from signal import signal, SIGTERM
from multiprocessing import Process

def test():
    def handler(signum, frame):
        print "child exit.", getpid()
        exit(0)

    signal(SIGTERM, handler)
    print "child start:", getpid()
    while True: sleep(1)

if __name__ == "__main__":
    p = Process(target = test)
    p.daemon = True   # 必須在 start() 前設置。
    p.start()

    sleep(2)    # 給點時間讓子進程進入 "狀態(tài)"。
    print "parent exit."

輸出:

child start: 12185
parent exit.
child exit. 12185

調用 terminate() 會立即強制終止子進程 (不會執(zhí)行任何清理操作)。有關狀態(tài)還有: is_alive()、pid、exitcode。

Pool

進程池。用多個可重復使用的后臺 (daemon) 進程執(zhí)行函數(shù),默認數(shù)量和 CPU 核相等。

from multiprocessing import Pool

def test(*args, **kwargs):
    print args
    print kwargs
    return 123
if __name__ == "__main__":
    pool = Pool()
    print pool.apply(test, range(3), dict(a=1, b=2))
    pool.close()
    pool.join()

輸出:

(0, 1, 2)
{'a': 1, 'b': 2}
123

調用 join() 等待所有工作進程結束前,必須確保用 close() 或 terminate() 關閉進程池。close() 阻止提交新任務,通知工作進程在完成全部任務后結束。該方法立即返回,不會阻塞等待。

使用異步模型時,callback 是可選的。

from multiprocessing import Pool
from time import sleep

def test(*args, **kwargs):
    sleep(2)
    return 123

def callback(ret):
    sleep(2)
    print "return:", ret

if __name__ == "__main__":
    pool = Pool()
    pool.apply_async(test, callback=callback)

    ar = pool.apply_async(test)
    print ar.get()

    pool.close()
    pool.join()

apply_async 返回 AsyncResult 實例,其 get([timeout])、wait()、successful() 等方法可獲知任務執(zhí)行狀態(tài)和結果。

map() 和 imap() 用于批量執(zhí)行,分別返回列表和迭代器結果。

from multiprocessing import Pool, current_process

def test(x):
    print current_process().pid, x
    return x + 100

def test2(s):
    print current_process().pid, s

if __name__ == "__main__":
    pool = Pool(3)

    print pool.map(test, xrange(5))
    pool.map(test2, "abc")

輸出:

1566 0
1567 1
1566 3
1568 2
1567 4
[100, 101, 102, 103, 104]

1566 a
1568 b
1567 c

參數(shù) chunksize 指定數(shù)據(jù)分塊大小,如果待處理數(shù)據(jù)量很大,建議調高該參數(shù)。

if __name__ == "__main__":
    pool = Pool(3)
    print pool.map(test, xrange(10), chunksize=2)

輸出:

1585 0    # 實際輸出順序可能不同。
1585 1
1586 2
1586 3
1587 4
1587 5
1585 6
1585 7
1586 8
1586 9
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]

Queue

Queue 是最常用的數(shù)據(jù)交換方法。參數(shù) maxsize 限制隊列中的數(shù)據(jù)項數(shù)量,這會影響 get/put 等阻塞操作。默認值無限制。

通常直接使用 JoinableQueue,其內部使用 Semaphore 進行協(xié)調。在執(zhí)行 put()、task_done()時調整信號量計數(shù)器。當 task_done() 發(fā)現(xiàn)計數(shù)值等于 0,立即通知 join() 解除阻塞。

from Queue import Empty
from multiprocessing import Process, current_process, JoinableQueue

def test(q):
    pid = current_process().pid
    while True:
        try:
        d = q.get(timeout=2)   # 阻塞 + 超時。照顧生產者未及生產情形。
        print pid, d
        q.task_done()
    except Empty:
        print pid, "empty"
        break

if __name__ == "__main__":
    q = JoinableQueue(maxsize=1000)

    map(q.put, range(5))     # 未超出隊列容量限制,不會阻塞。
    print "put over"

    for i in range(3):      # 創(chuàng)建多個 consumer。
        Process(target=test, args=(q,)).start()

    q.join()       # 等待任務完成。
    print "task done"

輸出:

put over
2127 0
2127 1
2127 2
2127 3
2127 4
task done
2127 empty
2128 empty
2129 empty

或許你會考慮壓入同等數(shù)量的 None 作為結束標志,但無法保證每個 Consumer 都能獲取。

argparse

命令行參數(shù)解析模塊。原 optparse 已經停止開發(fā),建議替換為 argparse。

parser

ArgumentParser 默認解析來源 sys.argv,也可提供顯式參數(shù)進行解析。

構造參數(shù)中,通常只需關心 description 和 epilog。前者顯示程序標題,后者在幫助信息的尾部顯示詳細的版權、使用描述等。

>>> from argparse import ArgumentParser
>>> parser = ArgumentParser(description="Test Program", epilog="author:qyuhen")
>>> parser.add_argument("-x", help="xxx...")

>>> parser.print_help()
usage: ipython [-h] [-x X]

Test Program

optional arguments:
-h, --help show this help message and exit
-x X xxx...

author:qyuhen

方法 parse_args 顯式列表參數(shù)可用 string.split 或 shlex.split 分解。

>>> args = parser.parse_args("-x 123".split())
>>> args
Namespace(x='123')

argument

參數(shù)分為可選參數(shù) (optional) 和 位置參數(shù) (positional) 兩種,前者用指定前綴 (默認是 "-") 標識。

>>> parser = ArgumentParser()
>>> parser.add_argument("-name", help="name...")
>>> parser.add_argument("x", help="x...")

>>> parser.print_help()
usage: ipython [-h] [-name NAME] x

positional arguments:
x x...

optional arguments:
    -h, --help show this help message and exit
    -name NAME name...

>>> parser.parse_args("-name q.yuhen 123".split())
Namespace(name='q.yuhen', x='123')

可選參數(shù)名可以有多個,鍵值間可以有 "=",而且單字符名稱的參數(shù)鍵值可以合并。

>>> parser = ArgumentParser()
>>> parser.add_argument('-x', "-XX")

>>> parser.print_help()
usage: ipython [-h] [-x X]

optional arguments:
    -h, --help show this help message and exit
    -x X, -XX X

>>> parser.parse_args("-x 100".split()) # 普通方式
Namespace(x='100')

>>> parser.parse_args("-x=100".split()) # 使用等號
Namespace(x='100')

>>> parser.parse_args("-x100".split())  # 合并鍵值
Namespace(x='100')

>>> parser.parse_args("-XX 100".split()) # 其他名稱
Namespace(x='100')

>>> parser.parse_args("-XX100".split()) # 僅單字符名可以合并
error: unrecognized arguments: -XX100

如果參數(shù)值是包含空格的字符串,注意用引號或轉義處理。

>>> parser = ArgumentParser()
>>> parser.add_argument("-s")

>>> parser.parse_args(shlex.split("-s='a b c'")) # 不能用 string.split()
Namespace(s='a b c')

>>> parser.parse_args(shlex.split("-s=a\ b\ c"))
Namespace(s='a b c')

可選參數(shù)默認返回 None,可用 default 參數(shù)或 parser.set_defaults 方法指定默認值。如果參數(shù)是必須的,只需設定 required=True 即可。

>>> parser = ArgumentParser()
>>> parser.add_argument("-x", default=123)
>>> parser.add_argument("-y", required=True)

>>> parser.parse_args()
error: argument -y is required

>>> parser.parse_args("-y abc".split())
Namespace(x=123, y='abc')

除非用 dest 指定值存儲名稱,否則和參數(shù)名相同。metavar 用于修改參數(shù)值顯示標記,默認使用 dest 大寫名稱。metavar 不會影響 dest 設置。

>>> parser = ArgumentParser()
>>> parser.add_argument("-n", dest="name")
>>> parser.add_argument("-x", dest="x", metavar="value")

>>> parser.print_help()
usage: ipython [-h] [-n NAME] [-x value]

optional arguments:
    -h, --help show this help message and exit
    -n NAME
    -x value

>>> parser.parse_args("-n q.yuhen -x 123".split())
Namespace(name='q.yuhen', x='123')

type 參數(shù)用于指定值轉換函數(shù),比如內置函數(shù) int、float、file,也可以自定義函數(shù)。

>>> parser = ArgumentParser()
>>> parser.add_argument("-x", type=int)
>>> parser.add_argument("-s", type=lambda s: "s:"+s)

>>> parser.parse_args("-x 123 -s abc".split())
Namespace(s='s:abc', x=123)

nargs 指示參數(shù)值數(shù)量,默認為 1。除具體的數(shù)字外,還可以使用通配符。

  • : 0 或 1。
  • *: 0 或 N。
  • +: 1 或 N。
  • REMAINDER: 所有剩下的值。
>>> parser = ArgumentParser()
>>> parser.add_argument("-x", nargs="+")
>>> parser.add_argument("-y", nargs="")
>>> parser.add_argument("n", nargs=2)
>>> parser.add_argument("args", nargs=REMAINDER)

>>> parser.print_help()
usage: ipython [-h] [-x X [X ...]] [-y [Y]] n n ...

positional arguments:
    n
    args

optional arguments:
    -h, --help show this help message and exit
    -x X [X ...]
    -y [Y]
>>> parser.parse_args("-x x1 x2 -y y1 1 2 a b c -xxx".split())
Namespace(args=['a', 'b', 'c', '-xxx'], n=['1', '2'], x=['x1', 'x2'], y='y1')

action 用于指定參數(shù)取值行為。

  • store: 默認,僅存儲。
  • store_const: 返回 const 或 default 值。
  • store_true/store_false: 返回 True 或 False。
  • append: 合并多個同名參數(shù)值。
  • append_const: 合并多個不同名參數(shù)的 const 值,注意這些參數(shù)的 dest 必須相同。
  • count: 統(tǒng)計參數(shù)名出現(xiàn)的次數(shù),常見的就是 -vvvv 這樣表示 level 的參數(shù)。
  • version: 版本信息.
# 1. store_const: 提供參數(shù)時返回 const 值,否則返回 default。

>>> parser = ArgumentParser()
>>> parser.add_argument("-x", action="store_const", const=100)
>>> parser.add_argument("-y", action="store_const", const=100, default=1)

>>> parser.parse_args("-x".split())
Namespace(x=100, y=1)

>>> parser.parse_args("-x -y".split())
Namespace(x=100, y=100)

>>> parser.parse_args()
Namespace(x=None, y=1)
# 2. store_true/store_false: 顯式返回指定布爾值,否則返回相反值。

>>> parser = ArgumentParser()
>>> parser.add_argument("-x", action="store_true")
>>> parser.add_argument("-y", action="store_false")

>>> parser.parse_args("-x -y".split())
Namespace(x=True, y=False)

>>> parser.parse_args()
Namespace(x=False, y=True)
# 3. append: 將多個同名參數(shù)值合并成列表。

>>> parser = ArgumentParser()
>>> parser.add_argument("-x", action="append")

>>> parser.parse_args("-x 1 -x 2".split())
Namespace(x=['1', '2'])
# 4. append_const: 合并多個不同名參數(shù) const 值,注意所有合并參數(shù)的 dest 相同。

>>> parser = ArgumentParser()
>>> parser.add_argument("-x", dest="numbers", action="append_const", const=1)
>>> parser.add_argument("-y", dest="numbers", action="append_const", const=2)

>>> parser.parse_args("-x -y".split())
Namespace(numbers=[1, 2])
# 5. count: 通常用于統(tǒng)計 -vvv 這類 level 參數(shù),只能是單字符名。

>>> parser = ArgumentParser()
>>> parser.add_argument("--verbose", "-v", action="count")

>>> parser.parse_args("-vv".split())
Namespace(v=2)
# 6. version: 顯示版本信息。

>>> parser = ArgumentParser()
>>> parser.add_argument('--version', "-V", action='version', version='%(prog)s 2.0')

>>> parser.parse_args("--version".split())
ipython 2.0

choices 用于指定參數(shù)取值范圍。

>>> parser = ArgumentParser()
>>> parser.add_argument('-x', choices=range(1, 5), type=int)
>>> parser.add_argument('-s', choices=("a", "b"))

>>> parser.print_help()
usage: ipython [-h] [-x {1,2,3,4}] [-s {a,b}]

optional arguments:
    -h, --help show this help message and exit
    -x {1,2,3,4}
    -s {a,b}

>>> parser.parse_args("-x 2 -s a".split())
Namespace(s='a', x=2)

>>> parser.parse_args("-x 6".split())
error: argument -x: invalid choice: 6 (choose from 1, 2, 3, 4)

>>> parser.parse_args("-s abc".split())
error: argument -s: invalid choice: 'abc' (choose from 'a', 'b')

group

如果參數(shù)較多,分組顯示更便于查看。

>>> parser = ArgumentParser()

>>> group1 = parser.add_argument_group("group1", "group1 description...")
>>> group1.add_argument("x", help="xxx...")

>>> group2 = parser.add_argument_group("group2", "group2 description...")
>>> group2.add_argument("y", help="yyy...")
>>> group2.add_argument("z", help="zzz...")

>>> parser.print_help()
usage: ipython [-h] x y z

optional arguments:
    -h, --help show this help message and exit

group1:
    group1 description...

    x           xxx...

group2:
    group2 description...
    y           yyy...
    z           zzz...

組的另外一個作用就是互斥,僅允許組中的一個參數(shù)出現(xiàn)??蓪M設置 required=True。

>>> parser = ArgumentParser()

>>> group = parser.add_mutually_exclusive_group(required=True)
>>> group.add_argument("-x")
>>> group.add_argument("-y")

>>> parser.print_help()
usage: ipython [-h] (-x X | -y Y)

optional arguments:
    -h, --help show this help message and exit
    -x X
    -y Y
>>> parser.parse_args("-x 100 -y 200".split())
error: argument -y: not allowed with argument -x

>>> parser.parse_args("-x 100".split())
Namespace(x='100', y=None)

>>> parser.parse_args("-y 200".split())
Namespace(x=None, y='200')

ctypes

標準庫 ctypes 模塊可以非常方便地調用動態(tài)庫 (.so),這有助于解決安全和性能問題。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int add(int x, int y)
{
    return x + y;
}

void inc(int* x)
{
    *x += 1;
}

void cprint(char* s)
{
    printf("%s: %s\n", __func__, s);
}

編譯:

$ gcc -fPIC -shared -o test.so test.c

測試:

>>> from ctypes import *
>>> so = cdll.LoadLibrary("./test.so")

>>> so.add(10, 20)
30

>>> so.cprint("Hello, World")
cprint: Hello, World
22

>>> x = c_int(123)
>>> so.inc(byref(x))    # 傳入指針
124
>>> x
c_int(124)

當然也可以直接調用系統(tǒng)庫的函數(shù)。

>>> libc = cdll.LoadLibrary("libc.dylib") # Linux: libc.so.6

>>> libc.printf("Hi\n")
Hi
4

>>> import time
>>> time.time(), libc.time()
(1364284691.803043, 1364284691)
上一篇:函數(shù)下一篇:元類