2010-02-13 32 views
16

Me gustaría cargar un archivo .py en tiempo de ejecución. Este archivo .py es básicamente un archivo de configuración con el siguiente formato:cargar código python en tiempo de ejecución

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

Una vez cargado el archivo, me gustaría ser capaz de acceder var1, var2 y predicate_function. Para cada línea, la pasaré a la función de predicado, y si devuelve falso, lo ignoraré.

En cualquier caso, no estoy seguro de cómo cargar un archivo de Python en tiempo de ejecución y acceder a sus variables.

Aclaración: puede haber cualquier número de estos archivos de configuración que necesita para pasar al programa principal y no voy a conocer sus nombres hasta que el tiempo de ejecución. Google me dice que debería usar __import__. No estoy seguro de cómo usar correctamente ese método y luego acceder a las variables del archivo importado.

Respuesta

10

sólo tiene que ser capaz de especificar de forma dinámica las importaciones y luego obtener dinámicamente en las variables.

Digamos que su fichero de configuración es bar.py y se ve así:

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

A continuación, el código debería tener este aspecto:

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] 

consigo esta salida:

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

Entonces al menos tiene todas las variables y funciones. No conseguí exactamente lo que quería de las funciones predicativas, pero tal vez pueda obtenerlo por su cuenta ahora.

+0

¡Funcionó perfectamente, gracias el dedo índice! – Shahbaz

1

Si usted quiere tener un archivo de configuración que sólo será editado por el usuario cuando el programa no se está ejecutando, simplemente importar como un archivo normal de Python

decir.

main.py:

import config 
print config.var1 

config.py:

var="var12" 
var2 = 100.5 
+0

Puedo tener cualquier cantidad de dichos archivos de configuración, así que no puedo hacer un "archivo de configuración de importación". De lo contrario, esta sería la solución más simple :) – Shahbaz

2

En Python 2.*, execfile obras (recomiendo que pasan un diccionario específico y el acceso a las variables de allí - como la nota en los documentos dice que execfile no puede afectar el diccionario de la función de llamada locals()).

En Python 3.*, execfile se ha eliminado, también lo hacen, en su lugar:

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

Para acceder a otro módulo de Python, lo importa. execfile ha sido mencionado por un par de personas, pero es complicado y peligroso. execfile desordena su espacio de nombres, posiblemente incluso arruinando el código que está ejecutando. Cuando desee acceder a otro archivo fuente de Python, use la instrucción import.

Aún mejor sería no utilizar ningún archivo Python para la configuración, sino utilizar el módulo incorporado ConfigParser o un formato de serialización como JSON. De esta manera, sus archivos de configuración no permiten la ejecución de código arbitrario (posiblemente malicioso), no requieren que las personas conozcan Python para configurar su programa, y ​​pueden modificarse fácilmente mediante programación.

+0

En realidad, la razón por la que estoy convirtiendo mi configuración en un archivo python es porque quiero que el archivo de configuración contenga un par de funciones (predicado). De lo contrario, simplemente leería en un archivo de texto, dividiría las cadenas y leería en un diccionario. – Shahbaz

7

Si el módulo importado está en el camino de búsqueda normal, puede utilizar __import__.

Si es necesario cargar el módulo desde un camino arbitrario en el sistema de archivos, utilice imp.load_module.

Asegúrese de considerar las implicaciones de seguridad de código especificado por el usuario arbitraria de carga.

+0

+1 Conciso y simple (= pitónico) – 0xc0de

14

Como está escrito en python official documentation, si solo desea importar un módulo por nombre, puede buscarlo en el diccionario sys.modules después de usar __import__.

Suponiendo que su configuración es en myproject.mymodule, lo haría así:

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... 

También puede utilizar el valor de retorno de __import__ declaración, sino que tendrá que entender completamente how python works with namespaces and scopes.

+2

mmh, no, en mi ejemplo, devolvería el módulo 'myproject' y no' myproject.mymodule'. Directamente del documento: _Cuando la variable de nombre tiene el formato package.module, normalmente, se devuelve el paquete de nivel superior (el nombre hasta el primer punto), no el módulo nombrado por nombre._ –

2

Estoy un poco tarde a la fiesta, pero yo quiero presentar una respuesta alternativa, no obstante.

Si desea importar código sin afectar el espacio de nombres global del módulo, puede crear un módulo anónima (utilizando types.ModuleType) y la carga de código arbitrario en el mismo (usando compile y exec). Por ejemplo, así:

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__ 

A continuación, puede acceder a las variables como config_module.var1, & c.

0

Desde la versión de Python no se ha mencionado con claridad, vale la pena señalar que el módulo imp ya no se utiliza en las últimas versiones de Python a favor del módulo importlib. Example here.

Cuestiones relacionadas