2010-09-23 17 views
217

Я хочу запустить скрипт Python из другого сценария Python. Я хочу передать переменные, как я бы использовал в командной строке.Запустите скрипт python из другого скрипта python, передав в args

К примеру, я бы запустить свой первый сценарий, который будет перебирать список значений (0,1,2,3) и передавать их на 2-й сценарий script2.py 0 затем script2.py 1 и т.д.

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

execfile("script2.py 1") 

Но он не принимает правильные значения. Когда я распечатываю sys.argv в файле script2.py, это исходный командный вызов для первого скрипта: «[C: \ script1.py»].

Я не хочу менять исходный скрипт (например, script2. .. ру в моем примере), так как я не являюсь его

Я полагаю, что там должен быть способ сделать это, я просто запутался, как вы это делаете

+0

Вопрос в том, знаете ли вы имя сценария (затем импортируете его) или если вы не знаете имя скрипта во время программирования (тогда используйте subprocess.call). Во втором случае этот вопрос также не будет дублировать. Потому что вопрос не дает понять, что это тоже не очень хорошо. – Trilarion

+0

@Trilarion: неправильно. Вы можете импортировать модуль python, даже если его имя генерируется во время выполнения. – jfs

+0

@ J.F.Sebastian Хорошо. Как побочное замечание: этот способ не очень хорошо освещен каким-либо ответом здесь или в связанном вопросе, за исключением частично в http://stackoverflow.com/a/1186840/1536976. – Trilarion

ответ

238

Попробуйте использовать os.system:

os.system("script2.py 1") 

execfile отличается тем, что предназначен для запуска nce операторов Python в текущем контексте . Вот почему sys.argv не изменился для вас.

+36

Я считаю, что обычно рекомендуется использовать 'subprocess.Popen' над' os.system': http://docs.python.org/library/subprocess.html#replacing-os-system. – katrielalex

+9

Да, это то, что говорит «os.system». Однако для простых целей 'os.system' - это самый простой способ выполнить задание. Конечно, это зависит от ваших потребностей. –

+2

Вы также можете использовать subprocess.check_call(). – MarioVilas

81

Это по своей сути неправильная вещь. Если вы используете скрипт Python из другого скрипта Python, вы должны общаться с помощью Python, а не через ОС:

import script1 

В идеальном мире, вы будете иметь возможность вызвать функцию внутри script1 непосредственно:

for i in range(whatever): 
    script1.some_function(i) 

При необходимости вы можете взломать sys.argv. Существует аккуратный способ сделать это, используя менеджер контекста, чтобы гарантировать, что вы не вносите никаких постоянных изменений.

import contextlib 
@contextlib.contextmanager 
def redirect_argv(num): 
    sys._argv = sys.argv[:] 
    sys.argv=[str(num)] 
    yield 
    sys.argv = sys._argv 

with redirect_argv(1): 
    print(sys.argv) 

Я думаю, что это предпочтительнее передавать все ваши данные в ОС и обратно; это просто глупо.

+9

Это может быть «неправильная» вещь, но что делать, если сценарий, который вам нужен для ссылки, не имеет никаких основных функций или функций ... импорт будет выполнять скрипт во время импорта, что, вероятно, не то, что вы хотите (и вы не хотите реорганизовывать его, потому что люди также используют этот скрипт как есть). os/subprocess может иметь дело с таким случаем –

+0

Правда ... но это другой вопрос ИМО! – katrielalex

+4

Не получится ли это для многопоточных скриптов? – MarioVilas

70

В идеале, сценарий Python вы хотите запустить будет создан с кодом, как это ближе к концу:

def main(arg1, arg2, etc): 
    # do whatever the script does 


if __name__ == "__main__": 
    main(sys.argv[1], sys.argv[2], sys.argv[3]) 

Другими словами, если модуль вызывается из командной строки, он разбирает параметры командной строки, а затем вызывает другую функцию, main(), чтобы выполнить фактическую работу. (Фактические аргументы будут меняться, и синтаксический анализ может быть более вовлеченными.)

Если вы хотите вызвать такой скрипт из другого скрипта Python, однако, вы можете просто import его и называют modulename.main() напрямую, а не через операционная система.

os.system будет работать, но это круговой (читаемый «медленный») способ сделать это, так как вы начинаете совершенно новый процесс интерпретации Python каждый раз, чтобы не было изюма.

+9

Re: «no raisin». Это не ошибка. Тем не менее, было интересно посмотреть, сколько времени потребуется кому-то, незнакомому с * Futurama *, «исправить» его в случайном вопросе переполнения стека: два года и три месяца. :-) – kindall

+0

Я смеялся над «никаким изюмом» просто потому, что это была нелепая опечатка, а затем увидел ваш комментарий и нашел клип на YouTube. Еще смешнее. – armani

+0

У меня был скрипт без главного, но он мог ввести так: 1. Разделить функции defs и автономные операторы. 2. Разбирать аргумент в разделе «if __name __...». 3. отступать остальные утверждения под def main (...), и эта логика работает с параметрами метода. Затем мне удалось вызвать основной метод из другого сценария (например: единичный тест) –

21
import subprocess 
subprocess.call(" python script2.py 1", shell=True) 
+14

Возможно, вы захотите расширить свой ответ, чтобы объяснить, почему это лучший вариант, чем некоторые другие ответы, представленные здесь. –

+1

Как передать аргумент, но не как строку, например список? Есть ли другой вариант, чем передавать каждый элемент отдельно? – Michu93

+0

Не используйте оболочку = True, если это необходимо. –

25

Я думаю, что хорошая практика может быть чем-то вроде этого;

import subprocess 
cmd = 'python script.py' 

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 
out, err = p.communicate() 
result = out.split('\n') 
for lin in result: 
    if not lin.startswith('#'): 
     print(lin) 

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

os.system 
os.spawn* 
os.popen* 
popen2.* 
commands.* 

Использование общения(), а не .stdin.write, .stdout.read или .stderr.read, чтобы избежать тупиков в связи с какой-либо из других буферов OS труб заполнение и блокирование дочернего процесса. Read Here