Как лучше всего вызвать скрипт из другого скрипта?

308

У меня есть скрипт с именем test1.py, которого нет в модуле. У него просто есть код, который должен выполняться при запуске самого скрипта. Там нет функций, классов, методов и т. Д. У меня есть другой скрипт, который работает как служба. Я хочу вызвать test1.py из скрипта, работающего как сервис.

Например:

Файл test1.py

print "I am a test"
print "see! I do nothing productive."

Файл service.py

# Lots of stuff here
test1.py # do whatever is in test1.py

Я знаю об одном методе, который открывает файл, читает содержимое и в основном оценивает его. Я предполагаю, что есть лучший способ сделать это. Или, по крайней мере, я на это надеюсь.

Джош Смитон
источник
42
Лучший способ - написать методы и классы и использовать их
Амир,
3
Никто еще не опубликовал runpy.run_moduleответ ?!
Аран-Фей,

Ответы:

279

Обычный способ сделать это что-то вроде следующего.

test1.py

def some_func():
    print 'in test 1, unproductive'

if __name__ == '__main__':
    # test1.py executed as script
    # do something
    some_func()

service.py

import test1

def service_func():
    print 'service func'

if __name__ == '__main__':
    # service.py executed as script
    # do something
    service_func()
    test1.some_func()
АРС
источник
44
Что делать, если test1.pyнаходится в каком-то далеком каталоге?
Евгений Сергеев
3
@EvgeniSergeev Престола stackoverflow.com/questions/67631/...
Евгений Сергеев
18
Это действительно не отвечает на вопрос, правда? Вы не выполняете весь сценарий, вы выполняете некоторые функции из сценария, который вы импортируете.
gented
2
@GennaroTedesco: Вы ошибаетесь. import test1В service.pyдействительно выполнить весь скрипт (который только определяет , some_func()так как __name__ == '__main__'будет Falseв этом случае). Это звучит как все, что ОП хочет сделать. Этот ответ выходит за рамки этого, но определенно отвечает на вопрос, а затем и на некоторые.
Мартино
2
Если, скажем, test1.pyне содержит определения функции some_func()(а, например, просто несколько строк кода print("hello")), то ваш код не будет работать. В этом конкретном примере это работает, потому что вы по сути импортируете внешнюю функцию, которую впоследствии вызываете.
gented
144

Это возможно в Python 2, используя

execfile("test2.py")

См. Документацию для обработки пространств имен, если это важно в вашем случае.

В Python 3 это возможно с помощью (благодаря @fantastory)

exec(open("test2.py").read())

Тем не менее, вы должны рассмотреть возможность использования другого подхода; ваша идея (из того, что я вижу) не выглядит очень чистой.

balpha
источник
9
Непосредственно то, что мне нужно в Python 32, это exec (open ('test2.py'). read ())
fantastory
8
Этот подход выполняет сценарии в вызывающем пространстве имен. :)
dmvianna
6
чтобы передать аргументы командной строки в скрипт, вы можете редактировать sys.argvсписок.
Jfs
1
Более подробное описание эквивалентов Python 3: stackoverflow.com/questions/436198/…
John Y
2
Это не принимает аргументы (для передачи в файл PY)!
Апостол
71

По-другому:

Файл test1.py:

print "test1.py"

Файл service.py:

import subprocess

subprocess.call("test1.py", shell=True)

Преимущество этого метода в том, что вам не нужно редактировать существующий скрипт Python, чтобы поместить весь его код в подпрограмму.

Документация: Python 2 , Python 3

Дик Гудвин
источник
8
Я должен был использовать это, subprocess.call("./test1.py", shell=True)чтобы заставить это работать
asmaier
5
Не используйте, shell=Trueесли это необходимо.
Петр Доброгост
2
@PiotrDobrogost - не могли бы вы указать, в каких ситуациях это будет необходимо?
sancho.s ReinstateMonicaCellio
8
Это не будет работать на типичном Unix, где текущий каталог не находится в PATH. test1.pyдолжен быть исполняемым и иметь строку shebang ( #!/usr/bin/env python), и вы должны указать полный путь, или вам нужно предоставить исполняемый файл самостоятельно: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])где get_script_dir()определено здесь .
Jfs
5
Или subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Если вы хотите, чтобы test1.py оставался исполняемым с той же функциональностью, что и при вызове внутри service.py, сделайте что-то вроде:

test1.py

def main():
    print "I am a test"
    print "see! I do nothing productive."

if __name__ == "__main__":
    main()

service.py

import test1
# lots of stuff here
test1.main() # do whatever is in test1.py
Майкл Шнайдер
источник
3
Что делать, если у вас есть параметры времени выполнения?
Ярмарка Габриэля
13
import os

os.system("python myOtherScript.py arg1 arg2 arg3")  

Используя ОС вы можете совершать звонки прямо на ваш терминал. Если вы хотите быть еще более конкретным, вы можете объединить вашу входную строку с локальными переменными, т.е.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Алекс Мэйпли
источник
os.systemследует избегать вызовов , вы можете сделать то же самое с любым классом отPopen, Call,
user1767754
Из документации Python : Модуль подпроцесса предоставляет более мощные средства для запуска новых процессов и получения их результатов; использование этого модуля предпочтительнее, чем использование этой функции.
Big McLargeHuge
12

Вы не должны делать это. Вместо этого сделайте:

test1.py:

 def print_test():
      print "I am a test"
      print "see! I do nothing productive."

service.py

#near the top
from test1 import print_test
#lots of stuff here
print_test()
thedz
источник
1
когда вы импортируете test1, как он узнает, где находится файл? это должно быть в том же каталоге? что если его нет?
NULL. Чувак
8

Используйте import test1для 1-го использования - он выполнит скрипт. Для последующих вызовов обработайте скрипт как импортированный модуль и вызовите reload(test1)метод.

Когда reload(module)выполняется:

  • Код модулей Python перекомпилируется, и код уровня модуля выполняется повторно , определяя новый набор объектов, которые связаны с именами в словаре модуля. Функция init модулей расширения не вызывается

Простая проверка sys.modulesможет использоваться для вызова соответствующего действия. Чтобы ссылаясь на имя сценария в виде строки ( 'test1'), используйте ' импорт () встроенный.

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
гимель
источник
3
reloadушел в Python 3.
Петр Доброгост
1
импорт модуля не эквивалентен его запуску, например, рассмотрим if __name__ == "__main__":Guard. Могут быть и другие, более тонкие различия. Не оставляйте произвольный код на глобальном уровне. Поместите это в функцию и вызовите ее после импорта, как предложено вместо этого в принятом ответе
jfs
5

Я предпочитаю насморк :

#!/usr/bin/env python
# coding: utf-8

import runpy

runpy.run_path(path_name='script-01.py')
runpy.run_path(path_name='script-02.py')
runpy.run_path(path_name='script-03.py')
Флавио
источник
3

Почему бы просто не импортировать test1? Каждый скрипт Python является модулем. Лучшим способом было бы иметь функцию, например, main / run в test1.py, импортировать test1 и запустить test1.main (). Или вы можете выполнить test1.py как подпроцесс.

Анураг Униял
источник
3

Как уже упоминалось, runpyэто хороший способ запустить другие скрипты или модули из текущего скрипта.

Между прочим, для трассировщика или отладчика это довольно распространено, и при таких обстоятельствах такие методы, как прямой импорт файла или запуск файла в подпроцессе, обычно не работают.

Это также требует внимания, чтобы использовать execдля запуска кода. Вы должны предоставить надлежащее, run_globalsчтобы избежать ошибки импорта или некоторых других проблем. Обратитесь к runpy._run_codeподробностям.

Чао Чен
источник
0

Это пример с subprocessбиблиотекой:

import subprocess

python_version = '3'
path_to_run = './'
py_name = '__main__.py'

# args = [f"python{python_version}", f"{path_to_run}{py_name}"]  # Avaible in python3
args = ["python{}".format(python_version), "{}{}".format(path_to_run, py_name)]

res = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = res.communicate()

if not error_:
    print(output)
else:
    print(error_)
Беньямин Джафари
источник
1
Запуск Python как подпроцесс Python почти никогда не является правильным решением. Если вы используете подпроцесс, вам следует избегать, Popenесли функции более высокого уровня действительно не могут делать то, что вы хотите. В этом случае, check_callили runбудет делать все, что вам нужно, и больше, со значительно меньшими затратами в вашем собственном коде.
Трипли
0

Этот процесс несколько неортодоксален, но будет работать во всех версиях Python,

Предположим, что вы хотите выполнить сценарий с именем 'require.py' внутри условия 'if', затем используйте,

if condition:
       import recommend

Техника другая, но работает!

Эшвин Балани
источник