Qual è un'alternativa a execfile in Python 3?
-
22-07-2019 - |
Domanda
Sembra che siano stati cancellati in Python 3 in modo semplice per caricare rapidamente uno script rimuovendo execfile ()
C'è un'alternativa ovvia che mi manca?
Soluzione
Altri suggerimenti
Devi solo leggere il file ed eseguire il codice da solo. 2to3 sostituisce attualmente
execfile("somefile.py", global_vars, local_vars)
come
with open("somefile.py") as f:
code = compile(f.read(), "somefile.py", 'exec')
exec(code, global_vars, local_vars)
(La chiamata di compilazione non è strettamente necessaria, ma associa il nome file all'oggetto codice rendendo il debug un po 'più semplice.)
See:
Mentre exec (open (" nomefile "). read ())
viene spesso fornito in alternativa a execfile (" nomefile ")
, manca importante dettagli supportati da execfile
.
La seguente funzione per Python3.x è la più vicina possibile allo stesso comportamento dell'esecuzione diretta di un file. Corrisponde all'esecuzione di 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")
Note:
- Utilizza la lettura binaria per evitare problemi di codifica
- Garantito per chiudere il file (Python3.x lo avverte)
- Definisce
__main__
, alcuni script dipendono da questo per verificare se si stanno caricando come modulo o no per es.se __name__ == " __ main __ "
- L'impostazione di
__file__
è migliore per i messaggi di eccezione e alcuni script usano__file__
per ottenere i percorsi di altri file relativi a loro. -
Prende globali & amp; opzionali argomenti locali, modificandoli sul posto come
execfile
, in modo da poter accedere a qualsiasi variabile definita leggendo nuovamente le variabili dopo l'esecuzione. -
A differenza del
execfile
di Python2, questo non modifica lo spazio dei nomi corrente per impostazione predefinita. Per questo devi passare esplicitamente inglobals ()
& amp;locals ()
.
Come suggerito sulla mailing list python-dev recentemente, il modulo runpy potrebbe essere una valida alternativa. Citando da quel messaggio:
https://docs.python.org/3/library/ runpy.html # runpy.run_path
import runpy file_globals = runpy.run_path("file.py")
Esistono sottili differenze con execfile
:
run_path
crea sempre un nuovo spazio dei nomi. Esegue il codice come modulo, quindi non c'è differenza tra globali e locali (motivo per cui esiste solo un argomentoinit_globals
). I globi vengono restituiti.execfile
eseguito nello spazio dei nomi corrente o nello spazio dei nomi indicato. La semantica dilocals
eglobals
, se fornita, era simile a quella di local e globals all'interno di una definizione di classe.run_path
può non solo eseguire file, ma anche uova e directory (fare riferimento alla sua documentazione per i dettagli).
Questo è meglio, dal momento che prende i globali e i locali dal chiamante:
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)
Puoi scrivere la tua funzione:
def xfile(afile, globalz=None, localz=None):
with open(afile, "r") as fh:
exec(fh.read(), globalz, localz)
Se davvero dovevi ...
Se lo script che desideri caricare si trova nella stessa directory di quella che esegui, forse " import " farà il lavoro?
Se devi importare dinamicamente il codice la funzione integrata __ import __ e il modulo imp merita una visita.
>>> 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!"
Se usi Python 3.1 o versioni successive, dovresti anche dare un'occhiata a importlib .
Ecco cosa avevo ( file
è già assegnato al percorso del file con il codice sorgente in entrambi gli esempi):
execfile(file)
Ecco cosa l'ho sostituito con:
exec(compile(open(file).read(), file, 'exec'))
La mia parte preferita: la seconda versione funziona perfettamente in Python 2 e 3, il che significa che non è necessario aggiungere una logica dipendente dalla versione.
Nota che il modello sopra fallirà se stai usando le dichiarazioni di codifica PEP-263 che non sono ascii o utf-8. Devi trovare la codifica dei dati e codificarla correttamente prima di consegnarlo 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)
Inoltre, pur non essendo una soluzione Python pura, se stai usando IPython (come probabilmente dovresti comunque), puoi fare:
%run /path/to/filename.py
Il che è altrettanto facile.
Sono solo un principiante qui, quindi forse è pura fortuna se lo trovassi:
Dopo aver provato a eseguire uno script dal prompt dell'interprete > > > con il comando
execfile('filename.py')
per il quale ho ricevuto un " NameError: il nome 'execfile' non è definito " Ho provato un
molto semplice import filename
ha funzionato bene :-)
Spero che questo possa essere utile e grazie a tutti per i grandi suggerimenti, esempi e tutti quei pezzi di codice commentati magistralmente che sono di grande ispirazione per i nuovi arrivati!
Uso Ubuntu 16.014 LTS x64. Python 3.5.2 (impostazione predefinita, 17 novembre 2016, 17:05:23) [GCC 5.4.0 20160609] su Linux