python標準模組(三)

morra發表於2016-10-31

本文會涉及到的模組:

  1. subprocess
  2. logging

1. subprocess

可以執行shell命令的相關模組和函式有:

os.system
os.spawn
os.popen
--廢棄
popen2.* --廢棄
commands.* --廢棄,3.x中被移除

import commands

result = commands.getoutput('cmd')
result = commands.getstatus('cmd')
result = commands.getstatusoutput('cmd')

以上執行shell命令的相關的模組和函式的功能均在 subprocess 模組中實現,並提供了更豐富的功能。

(1) call

執行命令,返回狀態碼(命令正常執行返回0,報錯則返回1)

ret1=subprocess.call("ifconfig")
ret2=subprocess.call("ipconfig")
print(ret1)     #0
print(ret2)     #1


ret = subprocess.call(["ls", "-l"], shell=False)    #shell為False的時候命令必須分開寫
ret = subprocess.call("ls -l", shell=True)

(2) check_call

執行命令,如果執行成功則返回狀態碼0,否則拋異常

subprocess.check_call(["ls", "-l"])
subprocess.check_call("exit 1", shell=True)

(3) check_output

執行命令,如果執行成功則返回執行結果,否則拋異常

subprocess.check_output(["echo", "Hello World!"])
subprocess.check_output("exit 1", shell=True)

(4) subprocess.Popen(...)

用於執行復雜的系統命令

引數 註釋
args shell命令,可以是字串或者序列型別(如:list,元組)
bufsize 指定緩衝。0 無緩衝,1 行緩衝,其他 緩衝區大小,負值 系統緩衝
stdin, stdout, stderr 分別表示程式的標準輸入、輸出、錯誤控制程式碼
preexec_fn 只在Unix平臺下有效,用於指定一個可執行物件(callable object),它將在子程式執行之前被呼叫
close_sfs 在windows平臺下,如果close_fds被設定為True,則新建立的子程式將不會繼承父程式的輸入、輸出、錯誤管道。所以不能將close_fds設定為True同時重定向子程式的標準輸入、輸出與錯誤(stdin, stdout, stderr)。
shell 同上
cwd 用於設定子程式的當前目錄
env 用於指定子程式的環境變數。如果env = None,子程式的環境變數將從父程式中繼承。
universal_newlines 不同系統的換行符不同,True -> 同意使用 \n
startupinfo 只在windows下有效,將被傳遞給底層的CreateProcess()函式,用於設定子程式的一些屬性,如:主視窗的外觀,程式的優先順序等等
createionflags 同上
import subprocess
ret1 = subprocess.Popen(["mkdir","t1"])
ret2 = subprocess.Popen("mkdir t2", shell=True)

終端輸入的命令分為兩種:

  1. 輸入即可得到輸出,如:ifconfig
  2. 輸入進行某環境,依賴再輸入,如:python
import subprocess

obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)     #在cwd目錄下執行命令
import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
obj.stdin.close()

cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()

print(cmd_out)
print(cmd_error)
import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")

out_error_list = obj.communicate()
print(out_error_list)
import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate('print("hello")')
print(out_error_list)

2. logging

用於便捷記錄日誌且執行緒安全的模組,不會允許多個人同時操作,不會存在髒資料

(1) 簡單日誌輸出

import logging

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
 
OUTPUT:
WARNING:root:This is warning message

預設的日誌級別為WARNING,只有【當前寫等級】>=【日誌等級】時,日誌檔案才被記錄。由於info和debug的日誌等級都比warning小,所以上面的程式碼輸出為:“WARNING:root:This is warning message”

日誌級別大小關係如下,當然也可以自己定義日誌級別。
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

(2) 單檔案日誌

import logging
  
logging.basicConfig(filename='log.log',
                    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',
                    level=10) 
#只有【當前寫等級】大於10時,日誌檔案才被記錄。

logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
logging.log(10,'log')      

logging.basicConfig函式各引數:

函式以及引數 註釋
filename 指定日誌檔名
filemode 和file函式意義相同,指定日誌檔案的開啟模式,'w'或'a'
format 指定輸出的格式和內容,format可以輸出很多有用資訊,如上例所示
%(levelno)s 列印日誌級別的數值
%(levelname)s 列印日誌級別名稱
%(pathname)s 列印當前執行程式的路徑,其實就是sys.argv[0]
%(filename)s 列印當前執行程式名
%(funcName)s 列印日誌的當前函式
%(lineno)d 列印日誌的當前行號
%(asctime)s 列印日誌的時間
%(thread)d 列印執行緒ID
%(threadName)s 列印執行緒名稱
%(process)d 列印程式ID
%(message)s 列印日誌資訊
datefmt 指定時間格式,同time.strftime()
level 設定日誌級別,預設為logging.WARNING
stream 指定將日誌的輸出流,可以指定輸出到sys.stderr,sys.stdout或者檔案,預設輸出到sys.stderr,當stream和filename同時指定時,stream被忽略

(3) 多檔案日誌

對於上述記錄日誌的功能,只能將日誌記錄在單檔案中,如果想要設定多個日誌檔案,logging.basicConfig將無法完成,需要自定義檔案和日誌操作物件。

日誌一:

# 定義檔案
file_1_1 = logging.FileHandler('l1_1.log', 'a', encoding='utf-8')
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
file_1_1.setFormatter(fmt)

file_1_2 = logging.FileHandler('l1_2.log', 'a', encoding='utf-8')
fmt = logging.Formatter()
file_1_2.setFormatter(fmt)

# 定義日誌
logger1 = logging.Logger('s1', level=logging.ERROR)
logger1.addHandler(file_1_1)
logger1.addHandler(file_1_2)

# 寫日誌
logger1.critical('1111')

日誌二:

# 定義檔案
file_2_1 = logging.FileHandler('l2_1.log', 'a')
fmt = logging.Formatter()
file_2_1.setFormatter(fmt)

# 定義日誌
logger2 = logging.Logger('s2', level=logging.INFO)
logger2.addHandler(file_2_1)

如上述建立的兩個日誌物件

當使用【logger1】寫日誌時,會將相應的內容寫入 l1_1.log 和 l1_2.log 檔案中
當使用【logger2】寫日誌時,會將相應的內容寫入 l2_1.log 檔案中

相關文章