2010-02-13 3 views
16

Je voudrais charger un fichier .py lors de l'exécution. Ce fichier .py est essentiellement un fichier de configuration avec le format suivant:charger le code python à l'exécution

var1=value 
var2=value 
predicate_function=func line : <return true or false> 

Une fois que ce fichier est chargé, je voudrais être en mesure d'accéder var1, var2 et predicate_function. Pour chaque ligne, je vais la passer à la fonction de prédicat, et si elle renvoie false, je l'ignorerai.

Dans tous les cas, je ne sais pas comment charger un fichier python à l'exécution et accéder à ses variables.

Clarification: il peut y avoir un certain nombre de ces fichiers de configuration que je dois transmettre au programme principal et je ne connaîtrai pas leurs noms avant l'exécution. Google me dit que je devrais utiliser __import__. Je ne suis pas sûr comment utiliser correctement cette méthode, puis accéder aux variables du fichier importé.

Répondre

10

Vous avez juste besoin d'être capable de spécifier dynamiquement les importations, puis d'obtenir dynamiquement les variables.

Disons que votre fichier de configuration est bar.py et ressemble à ceci:

x = 3 
y = 4 
def f(x): return (x<4) 

Ensuite, votre code devrait ressembler à ceci:

import sys 

# somehow modnames should be a list of strings that are the names of config files 
# 
# you can do this more dynamically depending on what you're doing                          
modnames = ['bar'] 

for modname in modnames: 
    exec('import %s' % modname) 

for modname in modnames: 
    mod = sys.modules[modname] 
    for k in mod.__dict__: 
    if k[:2] != '__': 
     print modname, k, mod.__dict__[k] 

Je reçois cette sortie:

bar f <function f at 0x7f2354eb4cf8> 
bar x 3 
bar y 4 

Ensuite, vous avez au moins toutes les variables et les fonctions. Je n'ai pas tout à fait compris ce que vous vouliez des fonctions de prédicat, mais peut-être que vous pouvez obtenir cela par vous-même maintenant.

+0

A travaillé parfaitement, merci l'index! – Shahbaz

1

Si vous voulez avoir un fichier de configuration qui ne sera modifié par l'utilisateur lorsque le programme ne fonctionne pas, il suffit d'importer comme un fichier python normale

ie.

main.py:

import config 
print config.var1 

config.py:

var="var12" 
var2 = 100.5 
+0

Je peux avoir n'importe quel nombre de tels fichiers de configuration, donc je ne peux pas simplement faire un "fichier d'importation de config". Sinon, ce serait la solution la plus simple :) – Shahbaz

2

En Python 2.*, execfile œuvres (je vous recommande de passage d'un dictionnaire spécifique et l'accès aux variables à partir de là - que la note dans les docs dit, execfile ne peut pas affecter le dictionnaire locals() de la fonction d'appel).

En Python 3.*, execfile a été supprimé, il ne faut, à la place:

with open('thefile.py') as f: 
    exec(f.read(), somedict) 
7

Pour accéder à un autre module Python, vous importer. execfile a été mentionné par un couple de personnes, mais il est salissant et dangereux. execfile encombre votre espace de noms, peut-être même en train de bousiller le code que vous utilisez. Lorsque vous souhaitez accéder à un autre fichier source Python, utilisez l'instruction import.

Encore mieux ne serait pas d'utiliser un fichier Python pour la configuration du tout, mais plutôt d'utiliser le module intégré ConfigParser ou un format de sérialisation comme JSON. De cette façon, vos fichiers de configuration ne permettent pas l'exécution de code arbitraire (éventuellement malveillant), ne nécessite pas de connaître Python pour configurer votre programme, et peut facilement être modifié par programmation.

+0

En fait, la raison pour laquelle je crée un fichier python est parce que je veux que le fichier de configuration contienne quelques fonctions (prédicats). Sinon, je voudrais simplement lire dans un fichier texte, diviser les chaînes et lire dans un dict. – Shahbaz

7

Si le module importé est sur le chemin de recherche normal, vous pouvez utiliser __import__.

Si vous devez charger le module à partir d'un chemin arbitraire dans le système de fichiers, utilisez imp.load_module.

Assurez-vous de prendre en compte les implications de sécurité du chargement de code arbitrairement spécifié par l'utilisateur.

+0

+ 1 Concis et simple (= pythonique) – 0xc0de

14

Comme écrit dans le python official documentation, si vous voulez simplement importer un module par son nom, vous pouvez le rechercher dans le dictionnaire sys.modules après avoir utilisé __import__.

Supposant votre configuration est myproject.mymodule, vous feriez comme ça:

module_name = 'myproject.mymodule' 

import sys 
__import__(module_name) 
mymodule = sys.modules[module_name] 

# Then you can just access your variables and functions 
print mymodule.var1 
print mymodule.var2 
# etc... 

Vous pouvez également utiliser la valeur de retour de __import__ déclaration, mais vous devrez comprendre how python works with namespaces and scopes.

+2

mmh, non, dans mon exemple, il renverrait le module 'myproject' et non' myproject.mymodule'. Directement à partir de la doc: _Lorsque la variable name est de la forme package.module, normalement, le package de niveau supérieur (le nom jusqu'au premier point) est renvoyé, pas le module nommé par name._ –

2

Je suis un peu en retard à la fête, mais je veux présenter néanmoins une réponse alternative.

Si vous souhaitez importer le code sans affecter l'espace de noms global du module, vous pouvez créer un module anonyme (en utilisant types.ModuleType) et charger du code arbitraire dans (à l'aide compile et exec). Par exemple, comme ceci:

import types 

filename = "/path/to/your/file.py" 
with open(filename) as fp: 
    code = compile(fp.read(), filename, "exec") 
config_module = types.ModuleType("<config>") 
exec code in config_module.__dict__ 

Vous pouvez alors accéder aux variables comme config_module.var1, & c.

0

Depuis la version Python n'a pas été clairement mentionné, il convient de souligner que le module diablotin a été dépréciée dans les versions de Python nouvelles en faveur du module importlib. Example here.