Який найкращий спосіб викликати сценарій з іншого сценарію?


307

У мене є сценарій з ім'ям 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знаходиться в якомусь віддаленому каталозі?
Євгеній Сергєєв


18
Але це насправді не відповідає на питання, чи не так? Ви не виконуєте весь сценарій, ви виконуєте деякі функції в межах імпортованого сценарію.
помер

2
@GennaroTedesco: Ти помилився. import test1В service.pyдійсно виконати весь скрипт (який тільки визначає , some_func()так як __name__ == '__main__'буде Falseв цьому випадку). Це звучить як все, що хоче зробити ОП. Ця відповідь виходить за рамки цього, але, безумовно, відповідає на питання - а потім і деякі.
мартіно

2
Якщо, скажімо, test1.pyне містило визначення функції some_func()(а, наприклад, лише деяких рядків коду print("hello")), то ваш код не працював. У цьому конкретному прикладі це працює, тому що ви фактично імпортуєте зовнішню функцію, яку потім передзвонюєте.
позначено

144

Це можливо в Python 2 за допомогою

execfile("test2.py")

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

У Python 3 це можливо за допомогою (завдяки @fantastory)

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

Однак слід розглянути можливість використання іншого підходу; ваша ідея (з того, що я бачу) виглядає не дуже чисто.


9
безпосередньо те, що мені потрібно в python 32, це exec (open ('test2.py'). read ())
фантастика

8
Цей підхід виконує сценарії в просторі імен виклику. :)
dmvianna

6
щоб передати аргументи командного рядка до сценарію, ви можете редагувати sys.argvсписок.
jfs

1
Більш комплексне лікування на еквівалентах Python 3: stackoverflow.com/questions/436198/…
Джон Y

2
Це не приймає аргументи (передається у файл PY)!
Апостолос

70

Інший спосіб:

Файл test1.py:

print "test1.py"

Файл service.py:

import subprocess

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

Перевага цього методу полягає в тому, що вам не доведеться редагувати існуючий скрипт Python, щоб ввести весь його код у підпрограму.

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


7
Мені довелося скористатися, subprocess.call("./test1.py", shell=True)щоб це працювало
асмаєр

5
Не використовуйте, shell=Trueякщо це не потрібно.
Пьотр Доброгост

2
@PiotrDobrogost - Чи могли б ви вказати, які ситуації зробили б це необхідним?
sancho.s ReinstateMonicaCellio

7
Він не працюватиме на типовому 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")  

За допомогою os ви можете телефонувати безпосередньо на свій термінал. Якщо ви хочете бути ще більш конкретними, ви можете з'єднати вхідний рядок з локальними змінними, тобто.

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()

1
коли ви імпортуєте test1, як він знає, де знаходиться файл? чи має бути це в одному каталозі? що якщо його немає?
NULL.Dude

8

Використовуйте import test1для першого використання - він виконає сценарій. Для пізніших викликів розглядайте сценарій як імпортований модуль та викликайте reload(test1)метод.

Коли reload(module)виконується:

  • Код модулів Python перекомпілюється і код модуля наново виконується , визначаючи новий набір об'єктів, які пов'язані з іменами у словнику модуля. Функція init модулів розширення не викликається

Проста перевірка sys.modulesможе бути використана для виклику відповідних дій. Щоб і надалі посилатися на ім'я сценарію як на рядок ( 'test1'), використовуйте вбудований ' import ()' .

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')

3
reloadпішов у Python 3.
Piotr Dobrogost

1
імпорт модуля не є еквівалентним його запуску, наприклад, врахуйте if __name__ == "__main__":оберіг. Можуть бути й інші більш тонкі відмінності. Не залишайте довільний код на глобальному рівні. Поставте його у функцію та зателефонуйте після імпорту, як пропонується замість прийнятої відповіді
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

Чому б не просто імпортувати тест1? Кожен скрипт 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зробили б все, що потрібно, і більше, із значно меншим розміром сантехніки у власному коді.
tripleee

0

Цей процес дещо неортодоксальний, але він працює у всіх версіях python,

Припустимо, ви хочете виконати скрипт під назвою 'рекомендую.py' всередині умови 'якщо', тоді використовуйте,

if condition:
       import recommend

Техніка інша, але працює!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.