外部程序调用+装饰器-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(' '.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()) 

  

原文地址:https://www.cnblogs.com/hyzhang/p/7716243.html