Wat is een alternatief voor execfile in Python 3?

Het lijkt erop dat ze in Python 3 de gemakkelijke manier hebben geannuleerd om snel een script te laden door execfile()

te verwijderen

Is er een duidelijk alternatief dat ik mis?


Antwoord 1, autoriteit 100%

Volgens de documentatie, in plaats van

execfile("./filename") 

Gebruik

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

Zie:


Antwoord 2, autoriteit 51%

Het is de bedoeling dat je het bestand leest en de code zelf uitvoert. 2 tot 3 stroom vervangt

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

als

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

(De compileeraanroep is niet strikt nodig, maar het associeert de bestandsnaam met het code-object waardoor debuggen een beetje makkelijker wordt.)

Zie:


Antwoord 3, autoriteit 18%

Hoewel exec(open("filename").read())vaak wordt gegeven als alternatief voor execfile("filename"), mist het belangrijke details die execfileondersteund.

De volgende functie voor Python3.x komt zo dicht mogelijk in de buurt van hetzelfde gedrag als het rechtstreeks uitvoeren van een bestand. Dat komt overeen met het uitvoeren van 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")

Opmerkingen:

  • Gebruikt binaire lezing om coderingsproblemen te voorkomen
  • Gegarandeerd om het bestand te sluiten (Python3.x waarschuwt hiervoor)
  • Definieert __main__, sommige scripts zijn hiervan afhankelijk om te controleren of ze als module worden geladen of niet voor bijv. if __name__ == "__main__"
  • Het instellen van __file__is prettiger voor uitzonderingsberichten en sommige scripts gebruiken __file__om de paden van andere bestanden ten opzichte daarvan te krijgen.
  • Neemt optionele globals & locals-argumenten, door ze ter plekke aan te passen zoals execfiledoet – zodat u toegang hebt tot alle variabelen die zijn gedefinieerd door de variabelen na het uitvoeren terug te lezen.

  • In tegenstelling tot het execfilevan Python2 wijzigt dit nietde huidige naamruimte standaard. Daarvoor moet je expliciet globals()& locals().


Antwoord 4, autoriteit 16%

Zoals gesuggereerd op de python-devmailinglijst onlangs zou de module runpyeen haalbaar alternatief kunnen zijn. Citaat uit dat bericht:

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

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

Er zijn subtiele verschillen met execfile:

  • run_pathmaakt altijd een nieuwe naamruimte aan. Het voert de code uit als een module, dus er is geen verschil tussen globals en locals (daarom is er alleen een init_globalsargument). De globals worden geretourneerd.

    execfileuitgevoerd in de huidige naamruimte of de opgegeven naamruimte. De semantiek van localsen globals, indien gegeven, was vergelijkbaar met locals en globals binnen een klassedefinitie.

  • run_pathkan niet alleen bestanden uitvoeren, maar ook eieren en mappen (raadpleeg de documentatie voor details).


Antwoord 5, autoriteit 5%

Deze is beter, omdat het de globals en locals van de beller nodig heeft:

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)

6, Autoriteit 4%

U kunt uw eigen functie schrijven:

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

Als je echt nodig hebt om …


7, Autoriteit 2%

Hier is wat ik had (fileis al toegewezen aan het pad naar het bestand met de broncode in beide voorbeelden):

execfile(file)

Hier is wat ik heb vervangen door:

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

Mijn favoriete onderdeel: de tweede versie werkt prima in zowel Python 2 als 3, wat betekent dat het niet nodig is om versieafhankelijke logica toe te voegen.


Antwoord 8

Houd er rekening mee dat het bovenstaande patroon zal mislukken als u PEP-263-coderingsdeclaraties gebruikt
die geen ascii of utf-8 zijn. U moet de codering van de gegevens vinden en deze coderen
correct voordat u het aan exec() overhandigt.

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)

Antwoord 9

Vermijd exec()als je kunt. Voor de meeste toepassingen is het schoner om gebruik te maken van het importsysteem van Python.

Deze functie gebruikt ingebouwde importlibom een bestand uit te voeren als een daadwerkelijke module:

from importlib import util
def load_file_as_module(name, location):
    spec = util.spec_from_file_location(name, location)
    module = util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

Gebruiksvoorbeeld

Laten we een bestand hebben foo.py:

def hello():
    return 'hi from module!'
print('imported from', __file__, 'as', __name__)

en importeer het als een gewone module:

>>> mod = load_file_as_module('mymodule', './foo.py')
imported from /tmp/foo.py as mymodule
>>> mod.hello()
hi from module!
>>> type(mod)
<class 'module'>

Voordelen

Deze aanpak vervuilt geen naamvullen of rommel met uw $PATH, terwijl exec()Code rechtstreeks in de context van de huidige functie uitvoeren, waardoor potentieel naambotsingen veroorzaakt. Ook, moduleattributen zoals __file__en __name__worden correct ingesteld en CODE-locaties worden bewaard. Dus, als u een debugger hebt bijgevoegd of als de module een uitzondering verhoogt, krijgt u bruikbare traceerbacks.

Merk op dat een klein verschil van statische invoer is dat de module wordt geïmporteerd (uitgevoerd) telkens wanneer u load_file_as_module()uitvoert, en niet alleen één keer als bij de importsleutelwoord.


10

Ook, terwijl niet een pure python-oplossing, als u IPYTHON (zoals u waarschijnlijk hoe dan ook gebruikt), kunt u doen:

%run /path/to/filename.py

die even eenvoudig is.


11

Ik ben hier gewoon een newbie, dus misschien is het puur geluk als ik dit heb gevonden:

Na het proberen een script uit de tolk-prompt & GT; & GT; & GT; met het commando

   execfile('filename.py')

waarvoor ik een “NameError: name ‘execfile’ is notdefined” kreeg Ik probeerde een heel eenvoudige

   import filename

het werkte goed 🙂

Ik hoop dat dit nuttig kan zijn en ik dank jullie allemaal voor de geweldige hints, voorbeelden en al die meesterlijk becommentarieerde stukjes code die een geweldige inspiratie zijn voor nieuwkomers!

Ik gebruik Ubuntu 16.014 LTS x64. Python 3.5.2 (standaard, 17 november 2016, 17:05:23)
[GCC 5.4.0 20160609] op linux

Other episodes