O que é uma alternativa para execfile em Python 3?
-
22-07-2019 - |
Pergunta
Parece que eles cancelada em Python 3 todo o caminho fácil para rapidamente carregar um script removendo execfile()
Existe uma alternativa óbvia que eu estou ausente?
Solução
acordo com a documentação , em vez de
execfile("./filename")
Use
exec(open("./filename").read())
Veja:
Outras dicas
Você está apenas suposto ler o arquivo e exec o código você mesmo. 2to3 substitui atuais
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)
(A chamada de compilação não é estritamente necessário, mas ele associa o nome do arquivo com o objeto código de fazer a depuração de um pouco mais fácil.)
Veja:
Enquanto exec(open("filename").read())
muitas vezes é dado como uma alternativa para execfile("filename")
, ele perde detalhes importantes que execfile
suportadas.
A função a seguir para Python3.x é o mais perto que eu poderia começar a ter o mesmo comportamento que a execução de um arquivo diretamente. Isso partidas correndo 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:
- Usa leitura binária para evitar codificação problemas
- Garantido para fechar o arquivo (Python3.x adverte sobre isso)
- Define
__main__
, alguns scripts dependem deste para verificar se eles são o carregamento como um módulo ou não para por exemplo.if __name__ == "__main__"
- Definir
__file__
é mais agradável para mensagens de exceção e alguns scripts usam__file__
para obter os caminhos de outros arquivos relativos a eles. -
Toma globals opcionais e habitantes locais argumentos, modificá-los no local como
execfile
faz -. Assim você pode acessar quaisquer variáveis ??definidas através da leitura de volta as variáveis ??depois de executar -
Ao contrário
execfile
de python2 isto significa não modificar o namespace atual por padrão. Por que você tem que passar explicitamente noglobals()
&locals()
.
Como sugeriu na python-dev mailinglist recentemente, o runpy módulo pode ser uma alternativa viável. Citando a mensagem:
https://docs.python.org/3/library/ runpy.html # runpy.run_path
import runpy file_globals = runpy.run_path("file.py")
Existem diferenças sutis para execfile
:
-
run_path
sempre cria um novo namespace. Ele executa o código como um módulo, então não há nenhuma diferença entre globals e moradores (que é por isso que há apenas um argumentoinit_globals
). Os globals são devolvidos.execfile
executado no namespace atual ou o namespace dado. A semântica delocals
eglobals
, se for dada, foram semelhantes aos habitantes locais e globais dentro de uma definição de classe. -
run_path
não só pode executar arquivos, mas também ovos e diretórios (consulte a sua documentação para mais detalhes).
Este é o melhor, uma vez que leva os globals e moradores do chamador:
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)
Você pode escrever sua própria função:
def xfile(afile, globalz=None, localz=None):
with open(afile, "r") as fh:
exec(fh.read(), globalz, localz)
Se você realmente precisava ...
Se o script que deseja carga está no mesmo diretório que o que você correr, talvez "importação" vai fazer o trabalho?
Se você precisa de código de importação de forma dinâmica o built-in função __ importação __ eo módulo imp valem a pena olhar.
>>> 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 você estiver usando Python 3.1 ou posterior, você também deve dar uma olhada em importlib .
Aqui está o que eu tinha (file
já está atribuído ao caminho para o arquivo com o código fonte em ambos os exemplos):
execfile(file)
Aqui está o que eu substituí-lo com:
exec(compile(open(file).read(), file, 'exec'))
A minha parte favorita:. A segunda versão funciona muito bem tanto em Python 2 e 3, o que significa que não é necessário adicionar na lógica dependente da versão
Note que o padrão acima falhará se você estiver usando PEP-263 de codificação de declarações que não são ASCII ou UTF-8. Você precisa encontrar a codificação dos dados, e codificá-lo corretamente antes de entregá-lo para 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)
Além disso, embora não seja uma solução Python puro, se você estiver usando IPython (como você provavelmente deve de qualquer maneira), você pode fazer:
%run /path/to/filename.py
O que é igualmente fácil.
Eu sou apenas um novato aqui talvez por isso é pura sorte se eu encontrei isto:
Depois de tentar executar um script do intérprete pronta >>> com o comando
execfile('filename.py')
para o qual eu tenho um "NameError: nome 'execfile' não está definido" Eu tentei um muito básico
import filename
funcionou bem: -)
Espero que este pode ser útil e agradeço a todos por grandes dicas, exemplos e todas as peças magistral de código comentado que são uma grande inspiração para os recém-chegados!
Eu uso o Ubuntu LTS 16,014 x64. Python 3.5.2 (padrão, 17 de novembro de 2016, 17:05:23) [GCC 5.4.0 20160609] no linux