2 votes

extension de subprocess.Popen par héritage

En tant qu'administrateur système, je me retrouve souvent à écrire des scripts qui appellent des commandes via un sous-processus. Parfois, je ne veux pas que les commandes soient réellement exécutées, et je veux juste voir ce qui serait exécuté. Par conséquent, mes codes étaient remplis de lignes comme celle-ci :

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

Je pensais qu'un "mode test" serait très utile.

A titre d'exemple d'utilisation :

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

Imprime simplement la commande à émettre. Cela semble peut-être redondant, mais dans la vie réelle, j'appelle parfois des sous-processus avec des commandes très complexes, qui sont décidées en fonction de conditions déterminées dans le script (ci-dessus il y a un exemple avec someHostName )

Je l'ai utilisé comme un exemple de la manière d'étendre une fonction en surchargeant sa fonction init méthode, . Voici comment j'ai étendu subprocess.Popen pour répondre à mes besoins :

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

Cela fonctionne comme je l'attends, mais comme je n'ai jamais étendu une classe en surchargeant son __init__ Je m'interrogeais sur l'exactitude de cette méthode, ou en d'autres termes : Existe-t-il une manière plus pythique de faire cela ? Devrais-je utiliser super pour une meilleure compatibilité avec Python3 ?

4voto

Dietrich Epp Points 72865

Je n'utiliserais pas de sous-classe du tout, car il semble que vous ne souhaitiez pas modifier la fonctionnalité de l'interface de l'utilisateur. Popen objet. On dirait que vous voulez juste changer la fonctionnalité de son constructeur.

Je créerais un mannequin Popen qui ne fait qu'imprimer ses arguments. (Ceci est écrit en utilisant le style Python 3.x, mais il est assez facile de le traduire en 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

Vous pouvez alors déclencher l'utilisation de la classe fictive comme vous le souhaitez.

def Popen(*args, testmode=False, **kw):
    if testmode:
        return DummyPopen(*args, **kw)
    return subprocess.Popen(*args, **kw)

Ou même :

if testmode:
    Popen = DummyPopen
else:
    Popen = subprocess.Popen

Cela permet de tirer parti des conventions de typage de Python : tout objet ayant la même interface qu'un objet de type Popen est fonctionnellement indifférenciable d'un objet Popen tant que vous n'abusez pas de l'objet isinstance() trop.

Notez que les deux de ces méthodes vous permettent d'importer Popen du module.

from mymodule import Popen

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X