2010-09-23 267 views
217

我想從另一個Python腳本運行Python腳本。我想要像使用命令行一樣傳遞變量。從另一個python腳本運行python腳本,傳入參數

例如,我會跑我的,將通過值(0,1,2,3)的列表迭代第一個腳本,並通過那些到第二腳本script2.py 0然後script2.py 1

我發現SO 1186789這是一個類似的問題,但阿爾斯的答案調用函數,因爲我想運行整個腳本不只是一個函數,和balpha的答案調用腳本,但沒有參數。我將其改爲如下所示的測試:

execfile("script2.py 1") 

但它沒有正確接受變量。當我在script2.py中打印出sys.argv時,它是第一個腳本「['C:\ script1.py']」的原始命令調用。

我不是真的想要更改原始腳本(即script2。 。在我的例子PY),因爲我不擁有它

我想一定有辦法做到這一點,我只是困惑,你是怎麼做到的

+0

問題是如果您知道腳本的名稱(然後導入它),或者如果您在編程時不知道腳本的名稱(然後使用subprocess.call)。在第二種情況下,這個問題也不會重複。因爲這個問題沒有說清楚,所以也不是很好。 – Trilarion 2015-09-03 11:37:47

+0

@Trilarion:錯了。你可以導入一個python模塊,即使它的名字是在運行時生成的。 – jfs 2015-11-29 08:33:50

+0

@ J.F.Sebastian好的。作爲一個方面的評論:這種方式並沒有真正涵蓋任何答案或鏈接的問題,部分在http://stackoverflow.com/a/1186840/1536976。 – Trilarion 2015-11-29 10:05:05

回答

238

嘗試使用os.system

os.system("script2.py 1") 

execfile是不同的,因爲它被設計來運行一個seque在當前的執行上下文中的Python語句。這就是爲什麼sys.argv沒有爲你改變。

+36

我相信通常最好在'os.system'上使用'subprocess.Popen':http://docs.python.org/library/subprocess.html#replacing-os-system。 – katrielalex 2010-09-23 20:15:15

+9

是的,這就是'os.system'的幫助所說的。然而,對於簡單的用途來說'os.system'是完成工作的最簡單的方法。當然,這取決於你的需求。 – 2010-09-23 20:39:35

+2

您也可以使用subprocess.check_call()。 – MarioVilas 2013-03-13 11:01:19

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可以處理這種情況 – 2012-08-21 15:33:11

+0

真的......但這是一個不同的問題IMO! – katrielalex 2012-08-21 16:08:28

+4

多線程腳本不會失敗嗎? – MarioVilas 2013-03-13 11:01:02

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

回覆:「沒有葡萄乾。」這不是一個錯誤。然而,看到不熟悉* Futurama *的人需要多長時間才能在一個隨機堆棧溢出問題中「糾正」它:兩年零三個月。 :-) – kindall 2012-12-29 18:30:49

+0

因爲這是一個荒謬的錯字,我嘲笑「沒有葡萄乾」,然後看到你的評論,並在YouTube上找到一個剪輯。更有趣。 – armani 2013-05-20 15:51:56

+0

我有一個沒有main的腳本,但能夠這樣引入:1.分離函數defs和獨立語句2.在「if __name __...」部分下執行參數解析3.在def下壓縮其餘語句main(...)並使該邏輯對方法參數進行操作。然後我可以從另一個腳本調用主要方法(例如:單元測試) – 2013-05-28 18:00:55

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

您可能希望擴展您的答案,以解釋爲什麼這是一個比這裏介紹的其他答案更好的選項。 – 2013-11-12 12:29:15

+1

如何傳遞參數而不是字符串,例如列表?除了分別傳遞每個元素還有其他選擇嗎? – Michu93 2016-07-21 09:20:15

+0

除非必要,否則不要使用shell = True。 – 2017-10-09 19:29:06

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) 

根據文檔 subprocess模塊​​允許你產卵新工藝,連接到它們的輸入/輸出/錯誤管道,並獲得它們的返回代碼。該模塊打算更換幾個較舊的模塊和功能:

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

使用通信(),而不是.stdin.write,.stdout.read或.stderr.read避免死鎖由於任何其他OS管緩衝器的填補和阻止兒童進程。 Read Here