Pregunta

Parece que cancelaron en Python 3 toda la manera fácil de cargar rápidamente un script eliminando execfile ()

¿Hay una alternativa obvia que me falta?

¿Fue útil?

Solución

De acuerdo con la documentación , en lugar de

execfile("./filename") 

Uso

exec(open("./filename").read())

Ver:

Otros consejos

Se supone que solo debes leer el archivo y ejecutar el código tú mismo. La corriente 2to3 reemplaza

execfile("somefile.py", global_vars, local_vars)

como

with open("somefile.py") as f:
    code = compile(f.read(), "somefile.py", 'exec')
    exec(code, global_vars, local_vars)

(La llamada de compilación no es estrictamente necesaria, pero asocia el nombre de archivo con el objeto de código haciendo que la depuración sea un poco más fácil).

Ver:

Si bien exec (open (" filename "). read ()) a menudo se ofrece como una alternativa a execfile (" filename ") , pierde importancia detalles que execfile admite.

La siguiente función para Python3.x es lo más cercana posible a tener el mismo comportamiento que ejecutar un archivo directamente. Eso coincide con la ejecución de python /path/to/somefile.py .

def execfile(filepath, globals=None, locals=None):
    if globals is None:
        globals = {}
    globals.update({
        "__file__": filepath,
        "__name__": "__main__",
    })
    with open(filepath, 'rb') as file:
        exec(compile(file.read(), filepath, 'exec'), globals, locals)

# execute the file
execfile("/path/to/somefile.py")

Notas :

  • Utiliza lectura binaria para evitar problemas de codificación
  • Garantizado para cerrar el archivo (Python3.x advierte sobre esto)
  • Define __main__ , algunos scripts dependen de esto para verificar si se están cargando como un módulo o no, por ejemplo. if __name__ == " __ main __ "
  • Configurar __file__ es mejor para mensajes de excepción y algunos scripts usan __file__ para obtener las rutas de otros archivos en relación con ellos.
  • Toma globales opcionales & amp; argumentos locales, modificándolos en el lugar como lo hace execfile , para que pueda acceder a cualquier variable definida leyendo las variables después de ejecutarlas.

  • A diferencia del execfile de Python2, esto no modifica el espacio de nombres actual de forma predeterminada. Para eso tienes que pasar explícitamente en globals () & amp; locals().

Como sugerido en la lista de correo python-dev Recientemente, el módulo runpy podría ser una alternativa viable. Citando de ese mensaje:

  

https://docs.python.org/3/library/ runpy.html # runpy.run_path

import runpy
file_globals = runpy.run_path("file.py")

Hay diferencias sutiles en execfile :

  • run_path siempre crea un nuevo espacio de nombres. Ejecuta el código como un módulo, por lo que no hay diferencia entre globales y locales (es por eso que solo hay un argumento init_globals ). Se devuelven los globales.

    execfile ejecutado en el espacio de nombres actual o en el espacio de nombres dado. La semántica de localess y globals , si se da, eran similares a los locales y globales dentro de una definición de clase.

  • run_path no solo puede ejecutar archivos, sino también huevos y directorios (consulte su documentación para más detalles).

Este es mejor, ya que toma los globales y locales de la persona que llama:

import sys
def execfile(filename, globals=None, locals=None):
    if globals is None:
        globals = sys._getframe(1).f_globals
    if locals is None:
        locals = sys._getframe(1).f_locals
    with open(filename, "r") as fh:
        exec(fh.read()+"\n", globals, locals)

Podría escribir su propia función:

def xfile(afile, globalz=None, localz=None):
    with open(afile, "r") as fh:
        exec(fh.read(), globalz, localz)

Si realmente necesitaras ...

Si el script que desea cargar está en el mismo directorio que el que ejecuta, tal vez " import " hará el trabajo?

Si necesita importar dinámicamente el código, la función integrada __ import __ y el módulo imp vale la pena ver.

>>> import sys
>>> sys.path = ['/path/to/script'] + sys.path
>>> __import__('test')
<module 'test' from '/path/to/script/test.pyc'>
>>> __import__('test').run()
'Hello world!'

test.py:

def run():
        return "Hello world!"

Si está utilizando Python 3.1 o posterior, también debe consultar importlib .

Esto es lo que tenía ( file ya está asignado a la ruta del archivo con el código fuente en ambos ejemplos):

execfile(file)

Esto es con lo que lo reemplacé:

exec(compile(open(file).read(), file, 'exec'))

Mi parte favorita: la segunda versión funciona bien tanto en Python 2 como en 3, lo que significa que no es necesario agregar lógica dependiente de la versión.

Tenga en cuenta que el patrón anterior fallará si está utilizando declaraciones de codificación PEP-263 que no son ascii o utf-8. Necesita encontrar la codificación de los datos y codificarla correctamente antes de entregárselo a exec ().

class python3Execfile(object):
    def _get_file_encoding(self, filename):
        with open(filename, 'rb') as fp:
            try:
                return tokenize.detect_encoding(fp.readline)[0]
            except SyntaxError:
                return "utf-8"

    def my_execfile(filename):
        globals['__file__'] = filename
        with open(filename, 'r', encoding=self._get_file_encoding(filename)) as fp:
            contents = fp.read()
        if not contents.endswith("\n"):
            # http://bugs.python.org/issue10204
            contents += "\n"
        exec(contents, globals, globals)

Además, aunque no es una solución pura de Python, si está utilizando IPython (como probablemente debería hacerlo de todos modos), puede hacer:

%run /path/to/filename.py

Que es igualmente fácil.

Solo soy un novato aquí, así que tal vez sea pura suerte si encuentro esto:

Después de intentar ejecutar un script desde el indicador del intérprete > > > con el comando

    execfile('filename.py')

para el que obtuve un " NameError: el nombre 'execfile' no está definido " Probé un muy básico

    import filename

funcionó bien :-)

¡Espero que esto pueda ser útil y gracias a todos por las excelentes sugerencias, ejemplos y todas esas piezas de código magistralmente comentadas que son una gran inspiración para los recién llegados!

Uso Ubuntu 16.014 LTS x64. Python 3.5.2 (predeterminado, 17 de noviembre de 2016, 17:05:23) [GCC 5.4.0 20160609] en Linux

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top