web-dev-qa-db-fra.com

Quelle est une alternative à execfile dans Python 3?

Il semble qu'ils aient annulé dans Python 3 un moyen simple de charger rapidement un script en supprimant execfile()

Y a-t-il une alternative évidente qui me manque?

311
R S

Selon la documentation , au lieu de

execfile("./filename") 

Utilisation

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

Voir:

340
Pedro Vagner

Vous êtes simplement censé lire le fichier et exécuter le code vous-même. 2to3 actuel remplace

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

comme

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

(L'appel de compilation n'est pas strictement nécessaire, mais il associe le nom de fichier à l'objet de code, ce qui facilite un peu le débogage.)

Voir:

205
Benjamin Peterson

Alors que exec(open("filename").read()) est souvent donné comme alternative à execfile("filename"), il manque des détails importants pris en charge par execfile.

La fonction suivante pour Python3.x est aussi proche que possible du même comportement que l’exécution directe d’un fichier. Cela correspond à l'exécution 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")

Notes:

  • Utilise la lecture binaire pour éviter les problèmes d'encodage
  • Garanti de fermer le fichier (Python3.x en avertit)
  • Définit __main__, certains scripts en dépendent pour vérifier s’ils se chargent en tant que module ou non, par exemple. if __== "__main__"
  • Définir __file__ est plus approprié pour les messages d’exception et certains scripts utilisent __file__ pour obtenir les chemins d’autres fichiers les concernant.
  • Prend les arguments optionnels globals & locals, en les modifiant sur place comme execfile - pour que vous puissiez accéder à toutes les variables définies en relisant les variables après leur exécution.

  • Contrairement à execfile de Python2, ceci ne modifie pas l'espace de nom actuel par défaut. Pour cela, vous devez explicitement passer globals() & locals().

61
ideasman42

Comme suggéré sur la liste de diffusion python-dev récemment, le module runpy pourrait être une alternative viable. Citant ce message:

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

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

Il y a des différences subtiles à execfile:

  • run_path crée toujours un nouvel espace de noms. Il exécute le code en tant que module, il n'y a donc pas de différence entre globals et locaux (c'est pourquoi il n'y a qu'un argument init_globals.). Les globals sont retournés.

    execfile exécuté dans l'espace de nom actuel ou dans l'espace de nom donné. La sémantique de locals et globals, si elle était donnée, était similaire aux variables locales et globales d'une définition de classe.

  • run_path peut non seulement exécuter des fichiers, mais également des oeufs et des répertoires (reportez-vous à sa documentation pour plus de détails).

53
Jonas Schäfer

Celui-ci est meilleur, car il prend les globals et les locaux de l'appelant:

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)
19
Noam

Vous pouvez écrire votre propre fonction:

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

Si vous aviez vraiment besoin de ...

18
Evan Fosmark

Si le script que vous voulez charger se trouve dans le même répertoire que celui que vous avez exécuté, "importer" fera peut-être le travail?

Si vous devez importer dynamiquement du code, la fonction intégrée _ IMPORT _ et le module imp valent la peine d'être visionnés.

>>> 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 vous utilisez Python 3.1 ou version ultérieure, vous devez également consulter importlib .

11
ascobol

Voici ce que j'ai eu (file est déjà affecté au chemin du fichier avec le code source dans les deux exemples):

execfile(file)

Voici ce que j'ai remplacé par:

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

Ma partie préférée: la deuxième version fonctionne parfaitement dans Python 2 et 3, ce qui signifie qu'il n'est pas nécessaire d'ajouter une logique dépendant de la version.

9
ArtOfWarfare

Notez que le modèle ci-dessus échouera si vous utilisez des déclarations de codage PEP-263 qui ne sont ni ascii ni utf-8. Vous devez trouver le codage des données et le coder correctement avant de le transmettre à 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)
5
Eric

De même, bien qu'il ne s'agisse pas d'une solution pure Python, si vous utilisez IPython (comme vous devriez probablement le faire), vous pouvez procéder comme suit:

%run /path/to/filename.py

Ce qui est également facile.

3
R S

Je suis juste un débutant ici, alors peut-être que c'est de la pure chance si j'ai trouvé ceci:

Après avoir essayé d'exécuter un script à partir de l'invite d'interprète >>> avec la commande

    execfile('filename.py')

pour lequel j'ai un "NameError: le nom 'execfile' n'est pas défini" j'ai essayé un très basique

    import filename

ça a bien fonctionné :-)

J'espère que cela peut être utile et je vous remercie pour vos astuces, vos exemples et tous ces morceaux de code commentés de manière magistrale qui sont une excellente source d'inspiration pour les nouveaux arrivants!

J'utilise Ubuntu 16.014 LTS x64. Python 3.5.2 (défaut, 17 novembre 2016, 17:05:23) [GCC 5.4.0 20160609] sur linux

1
Claude