作为系统管理员,我发现自己多次编写通过子进程调用命令的脚本。有时,我不希望命令实际执行,我只想看看会执行什么。因此,我的代码如下所示:
alaroffcmd = 'someBinary -h %s' %someHostName
...
if options.tstmd:
print alaroffcmd
else:
chctxt = sp.Popen(alamoffcmd,shell=True, stdout=sp.PIPE)
...
我认为'testmode'会非常有用。
作为使用示例:
lsp=nPopen('ls -l',shell=True, stdout=sp.PIPE, testmode=True)
只打印要发出的命令。这似乎是多余的,但在现实生活中,我有时会使用一些非常复杂的命令调用子进程,这些命令是根据脚本中确定的条件决定的(上面有someHostName
的示例)
我将其用作an example how to extend a function by overriding it's init method,。以下是我如何扩展subprocess.Popen
以满足我的需求:
import subprocess as sp
class nPopen(sp.Popen):
def __init__(self, args, bufsize=0, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=False, shell=False,
cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0,testmode=False):
if testmode:
print args
return None
p = sp.Popen.__init__(self,args, bufsize, executable,
stdin, stdout, stderr,
preexec_fn, close_fds, shell,
cwd, env, universal_newlines,
startupinfo, creationflags)
return p
这可以按照我的预期工作,但由于我从未通过覆盖其__init__
方法扩展了一个类,所以我想知道这个的正确性,换句话说:
是否有更多的Pythonic方法来做到这一点?
我应该使用super
来获得更好的Python3兼容性吗?
答案 0 :(得分:3)
我根本不会使用子类,因为听起来你不想改变Popen
对象的功能。听起来你只想改变其构造函数的功能。
我会创建一个伪Popen
类,只打印出它的参数。 (这是使用Python 3.x样式编写的,但它很容易转换为Python 2.x.)
class DummyPopen(object):
def __init__(self, *args, **kw):
print('Popen({})'.format(
', '.join([repr(arg) for arg in args] +
['{}={!r}'.format(*pair) for pair in kw.items()])))
self.returncode = 1
def wait(self):
return 1
# et cetera
然后,您可以根据需要触发使用虚拟类。
def Popen(*args, testmode=False, **kw):
if testmode:
return DummyPopen(*args, **kw)
return subprocess.Popen(*args, **kw)
甚至:
if testmode:
Popen = DummyPopen
else:
Popen = subprocess.Popen
这利用了Python的“duck typing”约定 - 任何与Popen
对象具有相同接口的对象在功能上都与Popen
对象无法区分,只要你没有'滥用isinstance()
太多了。
请注意,这些方法的两个都允许您从模块中导入Popen
。
from mymodule import Popen