扩展subprocess.Popen通过继承

时间:2012-11-14 16:48:48

标签: python inheritance subprocess

作为系统管理员,我发现自己多次编写通过子进程调用命令的脚本。有时,我不希望命令实际执行,我只想看看会执行什么。因此,我的代码如下所示:

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兼容性吗?

1 个答案:

答案 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