外部程序调用+装饰器-16
Posted 午间小憩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了外部程序调用+装饰器-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的主要内容,如果未能解决你的问题,请参考以下文章