tutorial poo metodos clase python pythonpath dirname

python - poo - ¿Cómo determinar correctamente el directorio de scripts actual?



python poo tutorial (12)

Aquí hay una solución parcial, aún mejor que todas las publicadas hasta el momento.

import sys, os, os.path, inspect #os.chdir("..") if ''__file__'' not in locals(): __file__ = inspect.getframeinfo(inspect.currentframe())[0] print os.path.dirname(os.path.abspath(__file__))

Ahora esto funciona todas las llamadas pero si alguien usa chdir() para cambiar el directorio actual, esto también fallará.

Notas:

  • sys.argv[0] no va a funcionar, devolverá -c si ejecuta el script con python -c "execfile(''path-tester.py'')"
  • Publiqué una prueba completa en https://gist.github.com/1385555 y puede mejorarla.

Me gustaría ver cuál es la mejor manera de determinar el directorio actual de scripts en Python?

Descubrí que de dos a muchas formas de llamar al código python, es difícil encontrar una buena solución.

Aquí hay algunos problemas:

  • __file__ no está definido si el script se ejecuta con exec , 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 estar ubicado en otro directorio y que puede tener otro directorio actual.

Sé que no hay una solución perfecta, porque en algunos casos, pero estoy buscando el mejor enfoque que solucionó 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 puede modificarse dentro del script en ejecución.


El enfoque os.path... fue lo ''hecho'' en Python 2.

En Python 3, puede encontrar el directorio del script de la siguiente manera:

from pathlib import Path cwd = Path(__file__).parents[0]


En Python 3.4+ puedes usar el módulo pathlib más pathlib :

from inspect import currentframe, getframeinfo from pathlib import Path filename = getframeinfo(currentframe()).filename parent = Path(filename).resolve().parent


Espero que esto ayude: - Si ejecuta un script / módulo desde cualquier lugar, podrá acceder a la variable __file__ , que es una variable de módulo que representa la ubicación del script.

Por otro lado, si está usando el intérprete, no tiene acceso a esa variable, donde obtendrá un nombre NameError y os.getcwd() le dará el directorio incorrecto si está ejecutando el archivo desde en algún otro lugar.

This solución debe darle lo que está buscando en todos los casos:

from inspect import getsourcefile from os.path import abspath abspath(getsourcefile(lambda:0))

No lo he probado a fondo, pero resolvió mi problema.


Esto debería funcionar en la mayoría de los casos:

import os,sys dirname=os.path.dirname(os.path.realpath(sys.argv[0]))


Primero ... un par de casos de uso faltantes aquí si estamos hablando de formas de insertar código anónimo.

code.compile_command() code.interact() imp.load_compiled() imp.load_dynamic() imp.load_module() __builtin__.compile() loading C compiled shared objects? example: _socket?)

Pero, la verdadera pregunta es, ¿cuál es tu objetivo? ¿Estás tratando de imponer algún tipo de seguridad? ¿O solo te interesa qué se está cargando?

Si le interesa la security , el nombre de archivo que se está importando a través de exec / execfile es irrelevante; debe usar rexec , que ofrece lo siguiente:

Este módulo contiene la clase RExec, que admite los métodos r_eval (), r_execfile (), r_exec () y r_import (), que son versiones restringidas de las funciones estándar de Python eval (), execfile () y las instrucciones exec e import. El código ejecutado en este entorno restringido solo tendrá acceso a módulos y funciones que se consideren seguros; puede subclase RExec agregar o eliminar capacidades según lo desee.

Sin embargo, si esto es más una búsqueda académica ... aquí hay un par de enfoques tontos que quizás puedas profundizar un poco más en ...

Scripts de ejemplo:

./deep.py

print '' >> level 1'' execfile(''deeper.py'') print '' << level 1''

./deeper.py

print ''/t >> level 2'' exec("import sys; sys.path.append(''/tmp''); import deepest") print ''/t << level 2''

/tmp/deepest.py

print ''/t/t >> level 3'' print ''/t/t/t I can see the earths core.'' print ''/t/t << level 3''

./codespy.py

import sys, os def overseer(frame, event, arg): print "loaded(%s)" % os.path.abspath(frame.f_code.co_filename) sys.settrace(overseer) execfile("deep.py") sys.exit(0)

Salida

loaded(/Users/synthesizerpatel/deep.py) >> level 1 loaded(/Users/synthesizerpatel/deeper.py) >> level 2 loaded(/Users/synthesizerpatel/<string>) loaded(/tmp/deepest.py) >> level 3 I can see the earths core. << level 3 << level 2 << level 1

Por supuesto, esta es una forma intensiva de recursos para hacerlo, estarías rastreando todo tu código ... No muy eficiente. Pero, creo que es un enfoque novedoso, ya que continúa funcionando incluso a medida que se adentra en el nido. No puede anular ''eval''. Aunque puede anular execfile ().

Tenga en cuenta que este enfoque solo codifica exec / execfile, no ''import''. Para un enganche de carga de ''nivel'' de nivel superior, es posible que pueda usar use sys.path_hooks (Cortesía de la compilación de PyMOTW).

Eso es todo lo que tengo fuera de mi cabeza.


Si realmente desea cubrir el caso de que un script se llame a través de execfile(...) , puede usar el módulo de inspect para deducir el nombre del archivo (incluida la ruta). Por lo que yo sé, esto funcionará para todos los casos que enumeró:

filename = inspect.getframeinfo(inspect.currentframe()).filename path = os.path.dirname(os.path.abspath(filename))


Solo use os.path.dirname(os.path.abspath(__file__)) y examine muy cuidadosamente si existe una necesidad real para el caso en que se usa el exec . Podría ser un signo de diseño problemático si no puede usar su secuencia de comandos como un módulo.

Tenga en cuenta Zen of Python # 8 , y si cree que hay un buen argumento para un caso de uso donde debe funcionar para el exec , entonces háganos saber más detalles sobre el fondo del problema.


haría

import os cwd = os.getcwd()

¿Haz lo que quieras? No estoy seguro de qué quiere decir exactamente con el "directorio actual de scripts". ¿Cuál sería el resultado esperado para los casos de uso que proporcionó?


#!/usr/bin/env python import inspect import os import sys def get_script_dir(follow_symlinks=True): if getattr(sys, ''frozen'', False): # py2exe, PyInstaller, cx_Freeze path = os.path.abspath(sys.executable) else: path = inspect.getabsfile(get_script_dir) if follow_symlinks: path = os.path.realpath(path) return os.path.dirname(path) print(get_script_dir())

Funciona en CPython, Jython, Pypy. Funciona si el script se ejecuta usando execfile() ( sys.argv[0] y las __file__ basadas en __file__ fallarían aquí). Funciona si el script está dentro de un archivo zip ejecutable (/ un huevo) . 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.


import os import sys def get_script_path(): return os.path.dirname(os.path.realpath(sys.argv[0])) my_script_dir = get_script_path() print my_script_dir

Esto le da el directorio de la secuencia de comandos en la parte superior de la pila (es decir, el que se está ejecutando, no el de Python, que generalmente es el primero ejecutado, devolviendo C:/ )


os.path.dirname(os.path.abspath(__file__))

de hecho es lo mejor que vas a obtener.

No es habitual ejecutar una secuencia de comandos con exec / execfile ; normalmente debería usar la infraestructura del módulo para cargar scripts. Si debe usar estos métodos, le sugiero que configure __file__ en los globals que pasa al script para que pueda leer ese nombre de archivo.

No hay otra manera de obtener el nombre del archivo en código ejecutado: como nota, el CWD puede estar en un lugar completamente diferente.