Rutas relativas en Python

Estoy creando un script de ayuda simple para el trabajo que copiará un par de archivos de plantilla en nuestra base de código al directorio actual. Sin embargo, no tengo la ruta de acceso absoluta al directorio donde se almacenan las plantillas. Tengo una ruta relativa desde el script, pero cuando llamo al script, lo trata como una ruta relativa al directorio de trabajo actual. ¿Hay alguna manera de especificar que esta URL relativa sea de la ubicación del script en su lugar?

En el archivo que tiene el script, desea hacer algo como esto:

import os dirname = os.path.dirname(__file__) filename = os.path.join(dirname, 'relative/path/to/file/you/want') 

Esto le dará la ruta absoluta al archivo que está buscando. Tenga en cuenta que si está usando setuptools, probablemente debería usar su API de recursos de paquetes .

ACTUALIZACIÓN : Estoy respondiendo a un comentario aquí para poder pegar un ejemplo de código. 🙂

¿Tengo razón al pensar que __file__ no siempre está disponible (por ejemplo, cuando ejecuta el archivo directamente en lugar de importarlo)?

Supongo que te refieres a la __main__ comandos __main__ cuando mencionas ejecutar el archivo directamente. Si es así, ese no parece ser el caso en mi sistema (python 2.5.1 en OS X 10.5.7):

 #foo.py import os print os.getcwd() print __file__ #in the interactive interpreter >>> import foo /Users/jason foo.py #and finally, at the shell: ~ % python foo.py /Users/jason foo.py 

Sin embargo, sí sé que hay algunas peculiaridades con __file__ en las extensiones C. Por ejemplo, puedo hacer esto en mi Mac:

 >>> import collections #note that collections is a C extension in Python 2.5 >>> collections.__file__ '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib- dynload/collections.so' 

Sin embargo, esto genera una excepción en mi máquina con Windows.

necesita os.path.realpath (el ejemplo a continuación agrega el directorio principal a su ruta)

 import sys,os sys.path.append(os.path.realpath('..')) 

Como se menciona en la respuesta aceptada.

 import os dir = os.path.dirname(__file__) filename = os.path.join(dir, '/relative/path/to/file/you/want') 

Solo quiero añadir eso

la última cadena no puede comenzar con la barra invertida, de hecho ninguna cadena debe incluir una barra invertida

Debería ser algo como

 import os dir = os.path.dirname(__file__) filename = os.path.join(dir, 'relative','path','to','file','you','want') 

La respuesta aceptada puede ser engañosa en algunos casos, consulte este enlace para obtener más información.

Considera mi código:

 import os def readFile(filename): filehandle = open(filename) print filehandle.read() filehandle.close() fileDir = os.path.dirname(os.path.realpath('__file__')) print fileDir #For accessing the file in the same folder filename = "same.txt" readFile(filename) #For accessing the file in a folder contained in the current folder filename = os.path.join(fileDir, 'Folder1.1/same.txt') readFile(filename) #For accessing the file in the parent folder of the current folder filename = os.path.join(fileDir, '../same.txt') readFile(filename) #For accessing the file inside a sibling folder. filename = os.path.join(fileDir, '../Folder2/same.txt') filename = os.path.abspath(os.path.realpath(filename)) print filename readFile(filename) 

Consulte sys.path. Cuando se inicia al iniciar el progtwig, el primer elemento de esta lista, ruta [0], es el directorio que contiene el script que se utilizó para invocar al intérprete de Python.

Utilice esta ruta como la carpeta raíz desde la que aplica su ruta relativa

 >>> import sys >>> import os.path >>> sys.path[0] 'C:\\Python25\\Lib\\idlelib' >>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6 >>> os.path.join(sys.path[0], "path_to_libs") 'C:\\Python25\\Lib\\idlelib\\path_to_libs' 

Ya es 2018, y Python ya ha evolucionado a __future__ mucho tiempo. Entonces, ¿qué hay de usar el increíble pathlib viene con Python 3.4 para lograr la tarea en lugar de luchar con os , os.path , glob , shutil , etc.?

Así que tenemos 3 caminos aquí (posiblemente duplicados):

  • mod_path : que es la ruta del script de ayuda simple
  • src_path : que contiene un par de archivos de plantilla en espera de ser copiados.
  • cwd : directorio actual , el destino de esos archivos de plantilla.

y el problema es: no tenemos la ruta completa de src_path , solo sabemos que es una ruta relativa a mod_path .

Ahora resolvamos esto con el sorprendente pathlib :

 # Hope you don't be imprisoned by legacy Python code :) from pathlib import Path # `cwd`: current directory is straightforward cwd = Path.cwd() # `mod_path`: According to the accepted answer and combine with future power # if we are in the `helper_script.py` mod_path = Path(__file__).parent # OR if we are `import helper_script` mod_path = Path(helper_script.__file__).parent # `src_path`: with the future power, it's just so straightforward relative_path_1 = 'same/parent/with/helper/script/' relative_path_2 = '../../or/any/level/up/' src_path_1 = (mod_path / relative_path_1).resolve() src_path_2 = (mod_path / relative_path_2).resolve() 

En el futuro, es así de simple. :RE


Además, podemos seleccionar y verificar y copiar / mover esos archivos de plantilla con pathlib :

 if src_path != cwd: # When we have different types of files in the `src_path` for template_path in src_path.glob('*.ini'): fname = template_path.name target = cwd / fname if not target.exists(): # This is the COPY action with target.open(mode='wb') as fd: fd.write(template_path.read_bytes()) # If we want MOVE action, we could use: # template_path.replace(target) 

En lugar de usar

 import os dirname = os.path.dirname(__file__) filename = os.path.join(dirname, 'relative/path/to/file/you/want') 

como en la respuesta aceptada, sería más robusto usar:

 import inspect import os dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1])) filename = os.path.join(dirname, 'relative/path/to/file/you/want') 

porque usar __file__ devolverá el archivo desde el que se cargó el módulo, si se cargó desde un archivo, por lo que si se llama al archivo con el script desde otro lugar, el directorio devuelto no será correcto.

Estas respuestas proporcionan más detalles: https://stackoverflow.com/a/31867043/5542253 y https://stackoverflow.com/a/50502/5542253

Este código devolverá la ruta absoluta al script principal.

 import os def whereAmI(): return os.path.dirname(os.path.realpath(__import__("__main__").__file__)) 

Esto funcionará incluso en un módulo.

Hola, primero que todo deberías entender las funciones os.path.abspath (path) y os.path.relpath (path)

En resumen, os.path.abspath (ruta) hace una ruta relativa a la ruta absoluta . Y si la ruta proporcionada es en sí misma una ruta absoluta, la función devuelve la misma ruta.

de manera similar, os.path.relpath (ruta) hace una ruta absoluta a la ruta relativa . Y si la ruta proporcionada es en sí misma una ruta relativa, la función devuelve la misma ruta.

El siguiente ejemplo puede permitirle entender correctamente el concepto anterior :

Supongamos que tengo un archivo input_file_list.txt que contiene la lista de archivos de entrada que debe procesar mi script de Python.

D: \ conc \ input1.dic

D: \ conc \ input2.dic

D: \ Copyioconc \ input_file_list.txt

Si ve la estructura de carpetas anterior, input_file_list.txt está presente en la carpeta Copyofconc y los archivos a ser procesados ​​por el script de python están presentes en la carpeta conc.

Pero el contenido del archivo input_file_list.txt es como se muestra a continuación:

.. \ conc \ input1.dic

.. \ conc \ input2.dic

Y mi script en python está presente en D: drive.

Y la ruta relativa proporcionada en el archivo input_file_list.txt es relativa a la ruta del archivo input_file_list.txt .

Entonces, cuando el script de Python ejecute el directorio de trabajo actual (use os.getcwd () para obtener la ruta)

Como mi ruta relativa es relativa a input_file_list.txt , que es “D: \ Copyofconc” , tengo que cambiar el directorio de trabajo actual a “D: \ Copyofconc” .

Así que tengo que usar os.chdir (‘D: \ Copyofconc’) , por lo que el directorio de trabajo actual será “D: \ Copyofconc” .

Ahora, para obtener los archivos input1.dic y input2.dic , leeré las líneas “.. \ conc \ input1.dic” y luego usaré el comando

input1_path = os.path.abspath (‘.. \ conc \ input1.dic’) (para cambiar la ruta relativa a la ruta absoluta. Aquí el directorio de trabajo actual es “D: \ Copyofconc”, el archivo “. \ conc \ input1. Se debe acceder a dic “en relación con” D: \ Copyofconc “)

por lo que input1_path será “D: \ conc \ input1.dic”

Una alternativa que me funciona:

 this_dir = os.path.dirname(__file__) filename = os.path.realpath("{0}/relative/file.path".format(this_dir)) 

Lo que funcionó para mí es usar sys.path.insert . Luego especifiqué el directorio que necesitaba para ir. Por ejemplo, solo necesitaba subir un directorio.

 import sys sys.path.insert(0, '../') 

No estoy seguro de si esto se aplica a algunas de las versiones anteriores, pero creo que Python 3.3 tiene soporte de ruta relativa nativa.

Por ejemplo, el siguiente código debe crear un archivo de texto en la misma carpeta que la secuencia de comandos de python:

 open("text_file_name.txt", "w+t") 

(tenga en cuenta que no debe haber una barra diagonal o una barra invertida al principio si se trata de una ruta relativa)