2010-06-29 12 views
8

Este fragmento es de una respuesta anterior aquí en SO. Tiene aproximadamente un año (y la respuesta no fue aceptada). Soy nuevo en Python y estoy encontrando la ruta del sistema un verdadero dolor. Tengo algunas funciones escritas en scripts en diferentes directorios, y me gustaría poder importarlas a nuevos proyectos sin tener que saltar por los aros.¿Es esta la forma correcta de importar scripts de Python que residen en carpetas arbitrarias?

Este es el fragmento:

def import_path(fullpath): 
""" Import a file with full path specification. Allows one to 
    import from anywhere, something __import__ does not do. 
""" 
path, filename = os.path.split(fullpath) 
filename, ext = os.path.splitext(filename) 
sys.path.append(path) 
module = __import__(filename) 
reload(module) # Might be out of date 
del sys.path[-1] 
return module 

Su desde aquí: How to do relative imports in Python?

me gustaría alguna información en cuanto a si lo puedo usar o no - y si hay efectos secundarios indeseables que puede no ser obvio para un novato.

que va a utilizarla algo como esto:

import_path(/home/pydev/path1/script1.py) 

script1.func1() 

etc

Es 'seguro' para utilizar la función de la manera que pretendo?

Respuesta

8

El enfoque "oficial" y completamente seguro es el módulo imp de la biblioteca estándar de Python.

Uso imp.find_module encontrar el módulo en su lista de precisión especificada de directorios aceptables - devuelve una tupla de 3 (file, pathname, description) - si no tiene éxito, es en realidad fileNone (pero también puede aumentar ImportError lo que debe utilizar un try/except para eso, así como para verificar if file is None:).

Si la búsqueda tiene éxito, llamar imp.load_module (en un try/finally para asegurarse de que cierre el archivo!) Con las anteriores tres parámetros tras el primero que debe ser la misma que pasó a namefind_module - devuelve el objeto del módulo (phew ;-).

+0

En 3.3, imp ha quedado obsoleto a favor de importlib. Sin embargo, en 3.2, no parece haber ningún uso equivalente de importlib, por lo que si necesita ejecutar en ambos entornos, ahórrese un dolor de cabeza y quédese con imp. – Yourpalal

0

Parece una especie de truco, pero por el momento, no puedo pensar en ningún efecto secundario no deseado que pueda ocurrir, al menos no mientras uses esto solo. guiones. Básicamente lo que hace es agregar temporalmente el directorio principal del archivo especificado (en su ejemplo, /home/pydev/path1/) a la lista de rutas que Python verifica cuando está buscando un módulo para importar.

El único riesgo que se me ocurre ahora podría surgir en un entorno multiproceso, donde dos o más hilos (o procesos) ejecutan esta función simultáneamente. Si el subproceso A quiere importar el módulo A desde la ruta dirA/A.py, y el subproceso B quiere importar el módulo B desde la ruta dirB/B.py, terminará con dirA y dirB en sys.path durante un tiempo breve. Y si hay un archivo llamado B.py en dirA, es posible que el hilo B encuentre eso (dirA/B.py) en lugar del archivo que está buscando (dirB/B.py), por lo que importa el módulo incorrecto. Por esta razón, no lo usaría en código de producción, o código que va a distribuir a otras personas (¡al menos no sin advertirles que este truco está aquí!). En una situación como esa, puede escribir una función más compleja que le permita especificar el archivo a importar sin interferir con el conjunto de rutas estándar. (Eso es lo que hace mod_python, por ejemplo)

0

Me preocuparía que el nombre del script se corresponda con un módulo que aparece anteriormente en la ruta. Para disipar este temor, reemplazaría completamente la ruta con una nueva lista que contiene solo el directorio que contiene el módulo, y luego la devolveré una vez que se haya completado la importación. Además, debe envolver esto en algún tipo de bloqueo para que varios subprocesos que intentan hacer lo mismo no interfieran entre sí.

0

Como se mencionó, considere la seguridad del hilo, si corresponde. Prefiero algo más cercano a una solución publicada en una publicación similar. Las principales diferencias a continuación: el uso de la inserción para especificar la prioridad de la importación, la restauración correcta de sys.path usando try ... finalmente, y la configuración del espacio de nombres global.

# inspired by Alex Martelli's solution to 
# http://stackoverflow.com/questions/1096216/override-namespace-in-python/1096247#1096247 
def import_from_absolute_path(fullpath, global_name=None): 
    """Dynamic script import using full path.""" 
    import os 
    import sys 

    script_dir, filename = os.path.split(fullpath) 
    script, ext = os.path.splitext(filename) 

    sys.path.insert(0, script_dir) 
    try: 
     module = __import__(script) 
     if global_name is None: 
      global_name = script 
     globals()[global_name] = module 
     sys.modules[global_name] = module 
    finally: 
     del sys.path[0] 
Cuestiones relacionadas