Что является альтернативой execfile в Python 3?
Кажется, они отменили в Python 3 все простой способ быстро загрузить скрипт, удалив execfile()
Есть ли очевидная альтернатива, которую я упускаю?
12 ответов
Согласно документации, вместо
execfile("./filename")
использование
exec(open("./filename").read())
Увидеть:
Вы просто должны прочитать файл и выполнить код самостоятельно. 2to3 текущий заменяет
execfile("somefile.py", global_vars, local_vars)
как
with open("somefile.py") as f:
code = compile(f.read(), "somefile.py", 'exec')
exec(code, global_vars, local_vars)
(Вызов компиляции не является строго необходимым, но он связывает имя файла с объектом кода, что немного облегчает отладку.)
Увидеть:
В то время как exec(open("filename").read())
часто дается в качестве альтернативы execfile("filename")
пропускает немало деталей, которые execfile
поддерживается.
Следующая функция для Python3.x максимально приближена к тому, чтобы иметь такое же поведение, как и непосредственное выполнение файла. Это соответствует бегу 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")
Заметки:
- Использует двоичное чтение, чтобы избежать проблем с кодированием
- Гарантированное закрытие файла (Python3.x предупреждает об этом)
- определяет
__main__
Некоторые сценарии зависят от этого, чтобы проверить, загружаются ли они как модуль или нет, например.if __name__ == "__main__"
- установка
__file__
лучше для сообщений об исключениях и использования некоторых скриптов__file__
чтобы получить пути других файлов относительно них. принимает необязательные аргументы globals & locals, изменяя их на месте как
execfile
делает - так что вы можете получить доступ к любым переменным, определенным путем чтения переменных после запуска.В отличие от Python2
execfile
это не изменяет текущее пространство имен по умолчанию. Для этого вы должны явно передать вglobals()
,
Как недавно было предложено в списке рассылки python-dev, модуль runpy может быть жизнеспособной альтернативой. Цитата из этого сообщения:
https://docs.python.org/3/library/runpy.html
import runpy file_globals = runpy.run_path("file.py")
Есть тонкие различия execfile
:
run_path
всегда создает новое пространство имен. Он выполняет код как модуль, поэтому нет разницы между глобальными и локальными (поэтому существует толькоinit_globals
аргумент). Глобалы возвращаются.execfile
выполняется в текущем пространстве имен или заданном пространстве имен. Семантикаlocals
а такжеglobals
если дано, было похоже на локальные и глобальные переменные внутри определения класса.run_path
может выполнять не только файлы, но также яйца и каталоги (подробности см. в документации).
Этот лучше, так как он берет глобальные и локальные от вызывающей стороны:
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)
Вы можете написать свою собственную функцию:
def xfile(afile, globalz=None, localz=None):
with open(afile, "r") as fh:
exec(fh.read(), globalz, localz)
Если вам действительно нужно...
Если скрипт, который вы хотите загрузить, находится в том же каталоге, что и тот, который вы запускаете, возможно, "import" выполнит эту работу?
Если вам нужно динамически импортировать код, стоит обратить внимание на встроенную функцию __ import__ и модуль imp.
>>> 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!"
Если вы используете Python 3.1 или более позднюю версию, вы также должны взглянуть на importlib.
Вот что у меня было (file
уже указан путь к файлу с исходным кодом в обоих примерах):
execfile(file)
Вот что я заменил:
exec(compile(open(file).read(), file, 'exec'))
Моя любимая часть: вторая версия прекрасно работает как в Python 2, так и в 3, то есть нет необходимости добавлять в зависящую от версии логику.
Для меня самый чистый подход - использовать importlib
и импортируйте файл как модуль по пути, например:
from importlib import util
def load_file(name, path):
spec = util.spec_from_file_location(name, path)
module = util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
Пример использования
Давай файл foo.py
:
print('i got imported')
def hello():
print('hello from foo')
Теперь просто импортируйте и используйте его как обычный модуль:
>>> foo = load_file('foo', './foo.py')
i got imported
>>> foo.hello()
hello from foo
Я предпочитаю эту технику прямым подходам вроде exec(open(...))
потому что он не загромождает ваши пространства имен и не беспокоит $PATH
.
Обратите внимание, что приведенный выше шаблон не будет работать, если вы используете объявления кодировки PEP-263, которые не являются ascii или utf-8. Вам нужно найти кодировку данных и правильно ее кодировать, прежде чем передать ее в 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)
Кроме того, хотя вы и не являетесь чистым Python-решением, если вы используете IPython (как вам, вероятно, следует в любом случае), вы можете сделать:
%run /path/to/filename.py
Что одинаково легко.
Я просто новичок здесь, так что, может быть, это просто удача, если я нашел это:
После попытки запустить скрипт из приглашения интерпретатора >>> с помощью команды
execfile('filename.py')
для которого я получил "NameError: имя 'execfile' не определено", я попробовал очень простой
import filename
это сработало хорошо:-)
Я надеюсь, что это может быть полезным, и спасибо всем за отличные советы, примеры и все эти виртуозно прокомментированные фрагменты кода, которые вдохновляют новичков!
Я использую Ubuntu 16.014 LTS x64. Python 3.5.2 (по умолчанию, 17 ноября 2016 г., 17:05:23) [GCC 5.4.0 20160609] в Linux
Найдите маршрут установки вашей папки (он у меня есть в C:\python34), затем выполните на обычной оболочке cmd
set path=%path%;c:\python34
теперь, когда вы инициализируете оболочку, перейдите в C:\python34\myscripts и используйте классическую команду
python filename.py