Me gustaría ver cuál es la mejor manera de determinar el directorio de script actual en python.
Descubrí que, debido a las muchas formas de llamar al código de Python, es difícil encontrar una buena solución.
Aquí hay algunos problemas:
__file__
no está definido si el script se ejecuta conexec
,execfile
__module__
se define solo en módulos
Casos de uso:
./myfile.py
python myfile.py
./somedir/myfile.py
python somedir/myfile.py
execfile('myfile.py')
(desde otro script, que puede ubicarse en otro directorio y que puede tener otro directorio actual.
Sé que no hay una solución perfecta, pero estoy buscando el mejor enfoque que resuelva la mayoría de los casos.
El enfoque más utilizado es, os.path.dirname(os.path.abspath(__file__))
pero esto realmente no funciona si ejecuta el script desde otro con exec()
.
Advertencia
Cualquier solución que use el directorio actual fallará, esto puede ser diferente según la forma en que se llama el script o se puede cambiar dentro del script en ejecución.
python
pythonpath
dirname
Bogdan
fuente
fuente
pathlib
solución de Ron Kalian si está utilizando Python 3.4 o superior: stackoverflow.com/a/48931294/1011724python myfile.py
desde un shell, funciona, pero ambos:!python %
y:!python myfile.py
desde vim fallan con El sistema no puede encontrar la ruta especificada. Esto es bastante molesto. ¿Alguien puede comentar sobre la razón detrás de esto y las posibles soluciones?Respuestas:
es de hecho lo mejor que vas a conseguir.
Es inusual ejecutar un script con
exec
/execfile
; normalmente debería usar la infraestructura del módulo para cargar scripts. Si debe utilizar estos métodos, le sugiero que configure__file__
elglobals
paso al script para que pueda leer ese nombre de archivo.No hay otra forma de obtener el nombre de archivo en el código ejecutado: como se observa, el CWD puede estar en un lugar completamente diferente.
fuente
Si realmente desea cubrir el caso por el que se llama un script
execfile(...)
, puede usar elinspect
módulo para deducir el nombre de archivo (incluida la ruta). Hasta donde yo sé, esto funcionará para todos los casos que enumeró:fuente
chdir()
antes de la función, cambiará el resultado. También llamar al script de Python desde otro directorio alterará el resultado, por lo que no es una buena solución.os.path.expanduser("~")
es una forma multiplataforma para obtener el directorio del usuario. Desafortunadamente, esa no es la mejor práctica de Windows sobre dónde pegar los datos de la aplicación.chdir()
antes de ejecutar el script; Produce el resultado correcto. Intenté llamar al script desde otro directorio y también funciona. Los resultados son los mismos que para lainspect.getabsfile()
solución basada .Funciona en CPython, Jython, Pypy. Funciona si el script se ejecuta usando
execfile()
(sys.argv[0]
y las__file__
soluciones basadas fallarían aquí). Funciona si el script está dentro de un archivo zip ejecutable (/ an egg) . Funciona si el script se "importa" (PYTHONPATH=/path/to/library.zip python -mscript_to_run
) desde un archivo zip; devuelve la ruta del archivo en este caso. Funciona si el script se compila en un ejecutable independiente (sys.frozen
). Funciona para enlaces simbólicos (realpath
elimina enlaces simbólicos). Funciona en un intérprete interactivo; devuelve el directorio de trabajo actual en este caso.fuente
getabsfile(..)
no se menciona en la documentacióninspect
? Aparece en la fuente que está vinculada desde esa página.getsourcefile()
,getfile()
que están documentados.En Python 3.4+ puedes usar el
pathlib
módulo más simple :fuente
Path(__file__)
(no necesita elinspect
módulo).Path(__file__)
da/path/to/script/currentscript.py
cuando el OP quería obtener/path/to/script/
parent = Path(__file__).resolve().parent
Eso es mucho mejor..joinpath()
(o el/
operador) para esto, no+
.El
os.path...
enfoque fue lo 'hecho' en Python 2.En Python 3, puede encontrar el directorio del script de la siguiente manera:
fuente
Path(__file__).parent
. Perocwd
es un nombre inapropiado, ese no es el directorio de trabajo actual , sino el directorio del archivo . Podrían ser lo mismo, pero ese no suele ser el caso.Simplemente use
os.path.dirname(os.path.abspath(__file__))
y examine con mucho cuidado si existe una necesidad real del caso en el queexec
se usa. Podría ser un signo de diseño problemático si no puede usar su script como módulo.Tenga en cuenta Zen of Python # 8 , y si cree que hay un buen argumento para un caso de uso en el que debe funcionar
exec
, háganos saber algunos detalles más sobre el fondo del problema.fuente
haría
¿Haz lo que quieras? No estoy seguro de qué quiere decir exactamente con el "directorio de script actual". ¿Cuál sería el resultado esperado para los casos de uso que proporcionó?
fuente
exec('myfile.py')
, igual que__file__
ysys.argv[0]
.Primero ... un par de casos de uso faltantes aquí si estamos hablando de formas de inyectar código anónimo ...
Pero, la verdadera pregunta es, ¿cuál es su objetivo? ¿Está tratando de imponer algún tipo de seguridad? ¿O simplemente está interesado en lo que se está cargando?
Si está interesado en la seguridad , el nombre de archivo que se importa a través de exec / execfile es intrascendente; debe usar rexec , que ofrece lo siguiente:
Sin embargo, si esto es más una búsqueda académica ... aquí hay un par de enfoques tontos en los que podrías profundizar un poco más ...
Guiones de ejemplo:
./deep.py
./deeper.py
/tmp/deepest.py
./codespy.py
Salida
Por supuesto, esta es una forma intensiva de recursos para hacerlo, estaría rastreando todo su código ... No es muy eficiente. Pero, creo que es un enfoque novedoso ya que continúa funcionando incluso a medida que profundizas en el nido. No puede anular 'eval'. Aunque tú puedes anular execfile ().
Tenga en cuenta que este enfoque solo codicia exec / execfile, no 'import'. Para un enganche de carga de 'módulo' de nivel superior, puede usar use sys.path_hooks (Escritura cortesía de PyMOTW).
Eso es todo lo que tengo fuera de mi cabeza.
fuente
Aquí hay una solución parcial, aún mejor que todas las publicadas hasta ahora.
Ahora esto funciona todas las llamadas, pero si alguien usa
chdir()
para cambiar el directorio actual, también fallará.Notas:
sys.argv[0]
no va a funcionar, volverá-c
si ejecuta el script conpython -c "execfile('path-tester.py')"
fuente
Esto debería funcionar en la mayoría de los casos:
fuente
Esperemos que esto ayude: - Si ejecuta un script / módulo desde cualquier lugar, podrá acceder a la
__file__
variable que es una variable de módulo que representa la ubicación del script.Por otro lado, si está utilizando el intérprete, no tiene acceso a esa variable, donde obtendrá un nombre
NameError
yos.getcwd()
le dará el directorio incorrecto si está ejecutando el archivo desde otro lugar.Esta solución debería darle lo que está buscando en todos los casos:
No lo he probado a fondo, pero resolvió mi problema.
fuente