2017-10-19 54 views
1

J'ai un certain nombre de fonctions qui doivent être appelées à partir de divers fichiers importés.Comment passer une chaîne en tant qu'objet à getattr python

Les fonctions sont formated le long des lignes de celle-ci:

a.foo 
b.foo2 
a.bar.foo4 
a.c.d.foo5 

et ils sont passés à mon script comme une chaîne brute.

Je suis à la recherche d'un moyen propre pour exécuter ces derniers, avec des arguments, et d'obtenir le retour des valeurs

En ce moment j'ai un système désordonné de diviser les cordes puis les nourrir à droite getattr appeler, mais cela se sent sorte de maladroit et est très peu évolutif. Y at-il un moyen que je peux simplement passer la partie de l'objet de getattr en tant que chaîne? Ou une autre façon de faire cela?

import a, b, a.bar, a.c.d 

if "." in raw_script: 
    split_script = raw_script.split(".") 
    if 'a' in raw_script: 
     if 'a.bar' in raw_script: 
      out = getattr(a.bar, split_script[-1])(args) 
     if 'a.c.d' in raw_script: 
      out = getattr(a.c.d, split_script[-1])(args) 
     else: 
      out = getattr(a, split_script[-1])(args) 
    elif 'b' in raw_script: 
     out = getattr(b, split_script[-1])(args) 

Répondre

1

Essayez ceci:

def lookup(path): 
    obj = globals() 
    for element in path.split('.'): 
     try: 
      obj = obj[element] 
     except KeyError: 
      obj = getattr(obj, element) 
    return obj 

Notez que cela gérer un chemin commençant par ne importe quel nom global, pas seulement vos a et b modules importés. S'il y a des soucis possibles avec une entrée non fiable fournie à la fonction, vous devriez commencer par une dict contenant les points de départ autorisés, et non la totalité des globals dict.

1

Il est difficile de dire à partir de votre question, mais il semble que vous ayez un outil de ligne de commande que vous exécutez comme my-tool <function> [options]. Vous pouvez utiliser importlib comme ceci, en évitant la plupart des appels getattr:

import importlib 

def run_function(name, args): 
    module, function = name.rsplit('.', 1) 
    module = importlib.import_module(module) 
    function = getattr(module, function) 
    function(*args) 

if __name__ == '__main__': 
    # Elided: retrieve function name and args from command line 
    run_function(name, args)