外部程序調用+裝飾器-16
pycharm簡介
現成的工具軟件,都可以完成一些功能(wget下載文件,ffmpeg多媒體視頻音頻文件的切割,轉換、合並視頻,錄制)
有時需要擴展一下,添加一點功能(free查看某一固定點內存使用)
有時需要把工具軟件組合起來(free、gnuplot畫圖表)
粘合各種外部程序和各種語言的庫,實現功能,方法:
os.system
subprocess
調用外部程序
os庫裏面的system函數,等於打開操作系統的shell,敲入一串命令,比如mspaint 命令
import os
os.system(‘mspaint‘)
print (‘after call‘)
直到外部程序退出了,代碼才接著往下執行
上面的最後一行打印的‘after call’直到我們關閉畫筆程序才會接著往下執行
組裝參數
工具軟件命令行支持參數,組裝出相應的參數
import os
os.system(‘mspaint e:\\1.png‘) #打開圖片
print (‘after call‘)
組裝復雜參數
ffmpeg
錄制屏幕右上角例子
#coding = utf8
import time,os
#輸出視頻文件
outputfile = ‘d:/data/bandicam/tmp/‘ + time.strftime(‘%Y%m%d_%H%M%S‘,time.localtime()) + ‘.mp4‘
#工具目錄
ffmpegDir = r‘d:/data/bandicam/tmp/ffmpeg.exe‘
setting = [
‘-y -rtbufsize 100M -f gdigrab -framerate 10‘ #幀率等
‘-offset_x 1000 -offset_y 0 -video_size 640*480, #錄制指定屏幕區域
‘-draw_mouse 1 -i desktop -c:v libx264’, #視頻編碼格式
‘-r 20 -preset medium -tune zerolatency -crt 35‘, #視頻壓縮參數
‘-pix_fmt yuv420p -fs 100M -movflags +faststart "%s"‘ %outputfile #大小限制等
]
#將參數組合起來
recordingCmdLine = ‘ ‘.join([ffmpegDir] + setting)
#查看命令內容
print (recordingCmdLine)
#執行命令錄制視頻
os.system(recordingCmdLine)
返回值
有些程序退出後會有一個退出碼
表示程序是否正確實現了其功能
Linux的命令 比如 ls ; echo $?(退出碼是0,表示命令執行成功)
python在調用這些程序時,退出碼作為返回值返回
Windows
如果是cmd.exe ,返回值就是進程的退出碼(退出碼為0)
Linux
會返回一個16位數字
低位字節 表示結束進程的信號數值
如果低位字節值為0,高位字節表示退出碼 512轉換為十六進制,兩位代表一個字節 ‘%x’ %512 -》200,低位0,高位是2;退出碼是2
可以通過返回值來判斷命令是否執行成功
import os
ret = os.system(‘cp /opt/file1 /home/hyz/file1‘)
if ret == 0:
print (‘file copied.‘)
else:
print (‘copy file failed!!‘)
subprocess 獲取第三方輸入內容
subprocess 庫裏面的check_output
import subprocess
#shell=True 表示使用終端shell執行程序,Windows下面就是cmd.exe
#就是我們python程序調用cmd.exe,再由cmd.exe執行參數命令
ret = subprocess.check_output(‘dir‘, shell = True,encoding = ‘gbk‘) encoding不填最終返回byte,填上參數自動解碼成Unicode
#如果有中文,需要decode,因為中文os,所以cmd.exe輸出是gbk編碼
print(ret)
#print (ret.decode(‘gbk‘))
subprocess.check_output 需要等到被調用程序退出,才能返回
subprocess庫裏面的Popen類,可以:被調用程序運行時候,就獲取其輸出的信息;運行時,輸入一些信息給被調用程序
subprocess.Popen(args,stdin =None,stout = None,stderr = None,shell = False,encoding = None)
args 參數要麽是列表,要麽是一個字符串
popen = Popen(args = [‘mspaint‘,r‘e:\1.jpg‘])
shell = True 表示用shell去執行,args 應該是字符串;
shell = False表示不是用shell去執行,args參數應該是一個列表
非阻塞式調用
非阻塞式調用外部程序
from subprocess import PIPE,Popen
process = Popen(
args = ‘mspaint‘,
shell = True
)
print (‘done‘)
調用外部程序後,python程序繼續執行
輸入輸出重定向
得到外部程序的輸出
from subprocess import PIPE,Popen
popen = Popen(
‘dir c:‘,
stout = PIPE, 管道,不指定會輸入到終端
shell = True,
encoding = ‘gbk‘)
output, err = popen.communicate()
print(output)
例
import time,trackback
try:
while True:
num = input(‘**請輸入數字:‘)
if num.isdigit():
print(‘立方是: %s‘ %int(num)**3)
except:
print(traceback.format_exc())
Popen = Popen(
‘python s4_1.py‘,
stdin = PIPE ,
stdout = PIPE,
stderr = PIPE,
shell = True,
encoding = ‘utf-8‘)
inputList = [‘3‘,‘4‘,‘37‘,‘55‘]
out,err = popen.communicate(‘\n‘.join(inoutList) #3回車,4回車,37回車,55 最後自動輸入 EOF(end of file)
print(out,err)
裝飾器
函數裏面定義函數
def foo():
def bar():
print (‘in bar()‘) 只在函數裏使用
print (‘in foo()’)
bar()
foo()
執行結果:
in foo()
in bar()
bar 的有效範圍:函數內部
在foo()函數外面使用bar()函數的辦法:
def foo():
def bar():
print (‘in bar()‘)
print (‘in foo()’)
return bar()
inner = foo() 返回bar指向bar()
inner() 相當於調用bar()
bar是一個函數對象
函數裏面定義類
def foo():
class My():
pass
print (‘in foo()‘)
My()
foo()
My的有效範圍:函數內部
定義類的靜態的方法時,就使用了裝飾器
@staticmethod
def jump():
print (‘3 meters high‘)
裝飾器的特點是用一個@開頭的字符串
在我們閱讀別人的代碼時,會經常碰到裝飾器
裝飾器通常用來裝飾函數
裝飾器主要用來給函數增加一點功能
一般裝飾器本身也是一個函數(callable)
我們可以想象成它包含了被裝飾的函數
例子
返回字符串的函數
def hello():
return ‘hello‘
def hi():
return ‘hi‘
我們需要返回值多兩個!
def endsign(func):
def wrapper():
return func() + ‘!!‘ 閉包
return wrapper
@endsign
def hello():
return ‘hello‘
#hell0 = endsign(hello)
print (hello()) 調用hello()
有參數的函數
要裝飾的函數參數都不同
def endsign(func):
def wrapper(*args,**kargs):
print(‘args:‘, args)
print(‘kargs:‘,kargs)
return func((*args,**kargs) + ‘!!‘
return wrapper
@endsign
def hello(arg1,arg2 = ‘ ‘):
return ‘hello %s %s ‘ %(arg1,arg2)
@endsign
def goodbye(targets):
return ‘goodbye %s ‘ %‘ ‘.join(targets)
裝飾器本身帶參數
需要的結尾可能不同
@endsign(‘!!‘)
def hello(arg1,arg2 = ‘ ‘):
return ‘hello %s %s ‘ %(arg1,arg2)
hello = endsign(‘!!‘)
@endsign(‘??‘)
def hi(arg1,arg2 = ‘ ‘);
return ‘hi %s %s‘ %(arg1,arg2)
hi = endsign(‘??‘)(hi)
def endsign(tail):
def innerOne(func):
def wrapper():
return func() + ‘ ‘ +tail
return wrapper
return innerOne
@enddign(‘??‘)
def hello():
return ‘hello‘
#hello = endsign(‘??‘) (hello)
print (hello())
endsigns(‘??‘)(hello) = innerone(hello) = wrapper
補充
我們在寫模塊文件的時候,對裏面的函數往往有些測試代碼,調用一下上面寫的函數
如果忘了註釋掉,在其他模塊導入這個模塊的時候,就會執行
def sayHello():
print("hello")
def sayGoodbye():
print("goodbye")
print (__name__)
if __name__ == "__main__" __name__只在入口模塊執行,作為入口模塊才會執行,導入到其他文件後不執行
print (‘exec testing‘)
sayHell0()
sayGoodbye()
可不可以有多個裝飾器?可以,定義多個裝飾器函數;可以定義多個裝飾器修飾一個函數
def endsign(func):
def wrapper():
return func() + ‘!!‘
return wrapper
def endsign2(func):
def wrapper():
return func() + ‘##‘
return wrapper
@endsign2
@endsign 先執行裏面的這個
def hello():
return ‘hello‘
hello = endsign(hello)
hell0 = endsign2(hello)
print (hello())
外部程序調用+裝飾器-16