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

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

操作系統(tǒng)

time

Unix-Like 系統(tǒng)使用自基準(zhǔn)點(diǎn)以來(lái)消逝的秒數(shù)來(lái)表達(dá)絕對(duì)時(shí)間。

  • 絕對(duì)時(shí)間: 某個(gè)絕對(duì)精確的時(shí)間值。如 2010-11-1 13:48:05 。
  • 相對(duì)時(shí)間: 相對(duì)于某個(gè)時(shí)間的前后差。如 5分鐘以前。
  • epoch: 基準(zhǔn)點(diǎn)。1970-01-01 00:00:00 UTC。
  • UTC: 協(xié)調(diào)世界時(shí)。世界不同時(shí)區(qū)的一個(gè)基準(zhǔn),比如中國(guó)為 UTC+8。
  • DST: 陽(yáng)光節(jié)約時(shí) (夏時(shí)制)。好在我國(guó)已經(jīng)取消了,真麻煩。

用 time() 返回自 epoch 以來(lái)的秒數(shù),gmtime()、localtime() 將其轉(zhuǎn)換為 struct_time 結(jié)構(gòu)體。

>>> 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 轉(zhuǎn)回 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 的轉(zhuǎn)換,注意返回的是 localtime 時(shí)間。

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

>>> t = time()

>>> d = datetime.fromtimestamp(t)  # localtime 時(shí)間
>>> 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)

相關(guān)函數(shù):

ctime: 將 epoch 轉(zhuǎn)換為字符串。 asctime: 將 struct_time 轉(zhuǎn)換為字符串。

>>> t = time()

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

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

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

>>> 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 的時(shí)差。 tzname: 當(dāng)前時(shí)區(qū)名稱。

>>> timezone / 3600
-8

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

threading

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

Thread

創(chuàng)建 Thread 實(shí)例,傳入待執(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

除了標(biāo)識(shí)符,還可以線程取個(gè)名字,這有助于調(diào)試。

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

>>> 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 屬性設(shè)為 True,那么表示這是一個(gè)背景線程,進(jìn)程退出時(shí)不會(huì)等待該線程結(jié)束。

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

>>> 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)   // 超時(shí)
...
...     print t.isAlive() // 檢查狀態(tài)
...     t.join()   // 再次等待
...
...     print "over"

>>> run()
__thread_start__
True
__thread_exit__
over!

Lock

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

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

>>> lock = RLock()

>>> def show(i):
...     with lock:     // 遞歸請(qǐng)求鎖
...         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 通過(guò)通過(guò)一個(gè)內(nèi)部標(biāo)記來(lái)協(xié)調(diào)多線程運(yùn)行。方法 wait() 阻塞線程執(zhí)行,直到標(biāo)記為 True。set() 將標(biāo)記設(shè)為 True,clear() 更改標(biāo)記為 False。isSet() 用于判斷標(biāo)記狀態(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

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

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

Condition

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

可以將已有的鎖對(duì)象傳給 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í)行。

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

當(dāng) wait() 釋放鎖后,其他線程也可進(jìn)入 wait 狀態(tài)。notifyAll() 激活所有等待線程,讓它們?nèi)屾i然后完成后續(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     // 至于誰(shuí)先搶到,就不好說(shuō)了。
Thread-1 3
Thread-1 4

Semaphore

Semaphore 通過(guò)一個(gè)計(jì)數(shù)器來(lái)限制可同時(shí)運(yùn)行的線程數(shù)量。計(jì)數(shù)器表示還可以運(yùn)行的線程數(shù)量,acquire() 遞減計(jì)數(shù)器,release() 則是增加計(jì)數(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 同時(shí)執(zhí)行。因?yàn)橛?jì)數(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 釋放信號(hào)量,3 開(kāi)始執(zhí)行。
Thread-3 1
Thread-3 2
Thread-3 3
Thread-3 4

Timer

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

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

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

Local

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

>>> 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 類(lèi)似,區(qū)別在于用進(jìn)程代替線程。這是規(guī)避 GIL,實(shí)現(xiàn)多核并發(fā)的常用方法。

Process

創(chuàng)建子進(jìn)程執(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)建子進(jìn)程,然后在新進(jìn)程中通過(guò) run() 執(zhí)行目標(biāo)函數(shù)。構(gòu)建參數(shù) args、kwargs 會(huì)傳遞給目標(biāo)函數(shù)。在父進(jìn)程中用 join() 等待并獲取子進(jìn)程退出狀態(tài),否則會(huì)留下僵尸進(jìn)程,除非父進(jìn)程先終止。

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

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

子進(jìn)程不會(huì)調(diào)用退出函數(shù),而且只有后臺(tái) (daemon) 進(jìn)程才可捕獲主進(jìn)程退出信號(hào),默認(rèn)處理自然是終止子進(jìn)程。另外,后臺(tái)進(jìn)程不能創(chuàng)建新的子進(jìn)程,這將導(dǎo)致僵尸出現(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() 前設(shè)置。
    p.start()

    sleep(2)    # 給點(diǎn)時(shí)間讓子進(jìn)程進(jìn)入 "狀態(tài)"。
    print "parent exit."

輸出:

child start: 12185
parent exit.
child exit. 12185

調(diào)用 terminate() 會(huì)立即強(qiáng)制終止子進(jìn)程 (不會(huì)執(zhí)行任何清理操作)。有關(guān)狀態(tài)還有: is_alive()、pid、exitcode。

Pool

進(jìn)程池。用多個(gè)可重復(fù)使用的后臺(tái) (daemon) 進(jìn)程執(zhí)行函數(shù),默認(rèn)數(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

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

使用異步模型時(shí),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 實(shí)例,其 get([timeout])、wait()、successful() 等方法可獲知任務(wù)執(zhí)行狀態(tài)和結(jié)果。

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

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ù)量很大,建議調(diào)高該參數(shù)。

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

輸出:

1585 0    # 實(shí)際輸出順序可能不同。
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 限制隊(duì)列中的數(shù)據(jù)項(xiàng)數(shù)量,這會(huì)影響 get/put 等阻塞操作。默認(rèn)值無(wú)限制。

通常直接使用 JoinableQueue,其內(nèi)部使用 Semaphore 進(jìn)行協(xié)調(diào)。在執(zhí)行 put()、task_done()時(shí)調(diào)整信號(hào)量計(jì)數(shù)器。當(dāng) task_done() 發(fā)現(xiàn)計(jì)數(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)   # 阻塞 + 超時(shí)。照顧生產(chǎn)者未及生產(chǎn)情形。
        print pid, d
        q.task_done()
    except Empty:
        print pid, "empty"
        break

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

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

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

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

輸出:

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

或許你會(huì)考慮壓入同等數(shù)量的 None 作為結(jié)束標(biāo)志,但無(wú)法保證每個(gè) Consumer 都能獲取。

argparse

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

parser

ArgumentParser 默認(rèn)解析來(lái)源 sys.argv,也可提供顯式參數(shù)進(jìn)行解析。

構(gòu)造參數(shù)中,通常只需關(guān)心 description 和 epilog。前者顯示程序標(biāo)題,后者在幫助信息的尾部顯示詳細(xì)的版權(quán)、使用描述等。

>>> 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) 兩種,前者用指定前綴 (默認(rèn)是 "-") 標(biāo)識(shí)。

>>> 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ù)名可以有多個(gè),鍵值間可以有 "=",而且單字符名稱的參數(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()) # 使用等號(hào)
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ù)值是包含空格的字符串,注意用引號(hào)或轉(zhuǎn)義處理。

>>> 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ù)默認(rèn)返回 None,可用 default 參數(shù)或 parser.set_defaults 方法指定默認(rèn)值。如果參數(shù)是必須的,只需設(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 指定值存儲(chǔ)名稱,否則和參數(shù)名相同。metavar 用于修改參數(shù)值顯示標(biāo)記,默認(rèn)使用 dest 大寫(xiě)名稱。metavar 不會(huì)影響 dest 設(shè)置。

>>> 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ù)用于指定值轉(zhuǎn)換函數(shù),比如內(nèi)置函數(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ù)量,默認(rèn)為 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: 默認(rèn),僅存儲(chǔ)。
  • store_const: 返回 const 或 default 值。
  • store_true/store_false: 返回 True 或 False。
  • append: 合并多個(gè)同名參數(shù)值。
  • append_const: 合并多個(gè)不同名參數(shù)的 const 值,注意這些參數(shù)的 dest 必須相同。
  • count: 統(tǒng)計(jì)參數(shù)名出現(xiàn)的次數(shù),常見(jiàn)的就是 -vvvv 這樣表示 level 的參數(shù)。
  • version: 版本信息.
# 1. store_const: 提供參數(shù)時(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: 將多個(gè)同名參數(shù)值合并成列表。

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

>>> parser.parse_args("-x 1 -x 2".split())
Namespace(x=['1', '2'])
# 4. append_const: 合并多個(gè)不同名參數(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)計(jì) -vvv 這類(lèi) 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...

組的另外一個(gè)作用就是互斥,僅允許組中的一個(gè)參數(shù)出現(xiàn)??蓪?duì)組設(shè)置 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

標(biāo)準(zhǔn)庫(kù) ctypes 模塊可以非常方便地調(diào)用動(dòng)態(tài)庫(kù) (.so),這有助于解決安全和性能問(wèn)題。

#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

測(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)

當(dāng)然也可以直接調(diào)用系統(tǒng)庫(kù)的函數(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ù)下一篇:元類(lèi)