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?
Selon la documentation , au lieu de
execfile("./filename")
Utilisation
exec(open("./filename").read())
Voir:
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:
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:
__main__
, certains scripts en dépendent pour vérifier s’ils se chargent en tant que module ou non, par exemple. if __== "__main__"
__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()
.
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).
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)
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 ...
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 .
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.
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)
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.
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