2

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

alaroffcmd = 'someBinary -h %s' %someHostName
...
if options.tstmd:       
   print alaroffcmd
else:
   chctxt = sp.Popen(alamoffcmd,shell=True, stdout=sp.PIPE) 
   ...

我在想“测试模式”会非常有用。

作为使用示例:

lsp=nPopen('ls -l',shell=True, stdout=sp.PIPE, testmode=True)

只会打印要发出的命令。这似乎是多余的,但在现实生活中,我有时会使用一些非常复杂的命令来调用子进程,这些命令是根据脚本中确定的条件决定的(上面有一个示例someHostName

我以此作为示例,如何通过覆盖函数的init方法来扩展函数。这是我扩展的方式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 兼容性吗?

4

1 回答 1

4

我根本不会使用子类,因为听起来您不想更改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 的“鸭子类型”约定——任何与对象具有相同接口的Popen对象在功能上与对象没有区别Popen,只要您不滥用isinstance()太多。

请注意,这两种Popen方法都允许您从模块导入。

from mymodule import Popen
于 2012-11-14T17:00:42.730 回答