1. 程式人生 > >外部程序調用+裝飾器-16

外部程序調用+裝飾器-16

增加 args str fun sign 結束 python程序 crt 功能

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