วิธีที่ดีที่สุดในการเรียกสคริปต์จากสคริปต์อื่นคืออะไร


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
วิธีที่ดีคือการใช้วิธีการเขียนและการเรียนและใช้พวกเขา
Aamir


3
ไม่มีใครโพสต์runpy.run_moduleคำตอบหรือยัง!
Aran-Fey

คำตอบ:


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ตั้งอยู่ในไดเรกทอรีที่ห่างไกล?
Evgeni Sergeev


18
สิ่งนี้ไม่ได้ตอบคำถามจริงๆใช่ไหม? คุณไม่ได้เรียกใช้งานสคริปต์ทั้งหมดคุณกำลังใช้งานบางฟังก์ชันจากภายในสคริปต์ที่คุณนำเข้า
gented

2
@GennaroTedesco: คุณเข้าใจผิด import test1ในservice.pyไม่แน่นอนดำเนินการทั้งสคริปต์ (ซึ่งมีเพียงกำหนดsome_func()ตั้งแต่__name__ == '__main__'จะเป็นFalseในกรณีที่) ฟังดูเหมือน OP ทั้งหมดต้องการจะทำ คำตอบนี้ไปไกลกว่านั้น แต่ตอบคำถามได้แน่นอน - แล้วก็บางข้อ
martineau

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

8
วิธีการนี้จะรันสคริปต์ภายในเนมสเปซการโทร :)
dmvianna

6
เพื่อส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งไปยังสคริปต์คุณสามารถแก้ไขsys.argvรายการ
jfs

1
การรักษาที่ครอบคลุมมากขึ้นสำหรับ Python 3 ที่เทียบเท่า: stackoverflow.com/questions/436198/…
John Y

2
สิ่งนี้ไม่ยอมรับอาร์กิวเมนต์ (จะถูกส่งผ่านไปยังไฟล์ PY)!
Apostolos

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)เพื่อทำให้มันทำงาน
asmaier

5
ห้ามใช้shell=Trueนอกเสียจากว่าจำเป็น
Piotr Dobrogost

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'])หรือ
บิ๊ก 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
ถ้าคุณมีพารามิเตอร์ runtime
งานกาเบรียลแฟร์

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ควรหลีกเลี่ยงคุณสามารถทำเช่นเดียวกันกับ Class ใด ๆ จากPopen, Call,
user1767754

จากเอกสาร Python : โมดูลย่อยให้บริการที่มีประสิทธิภาพยิ่งขึ้นสำหรับการวางไข่กระบวนการใหม่และดึงผลลัพธ์ การใช้โมดูลนั้นจะดีกว่าการใช้ฟังก์ชั่นนี้
บิ๊ก 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สำหรับการใช้งานครั้งที่ 1 - มันจะรันสคริปต์ สำหรับการเรียกใช้ในภายหลังให้ใช้สคริปต์เป็นโมดูลที่อิมพอร์ตและเรียกใช้reload(test1)เมธอด

เมื่อreload(module)ถูกดำเนินการ:

  • รหัสโมดูลของ Python นั้นจะถูกคอมไพล์ใหม่และโค้ดระดับโมดูลจะถูกเปิดใช้งานอีกครั้งโดยกำหนดชุดของออบเจ็กต์ใหม่ที่เชื่อมโยงกับชื่อในพจนานุกรมของโมดูล ไม่ได้เรียกใช้ฟังก์ชัน init ของโมดูลส่วนขยาย

sys.modulesสามารถใช้การตรวจสอบอย่างง่ายเพื่อเรียกการกระทำที่เหมาะสม เพื่ออ้างอิงถึงชื่อสคริปต์เป็นสตริง ( 'test1') ใช้builtin ' 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__":Guard อาจมีความแตกต่างที่ลึกซึ้งยิ่งขึ้นอื่น ๆ อย่าปล่อยให้รหัสโดยพลการในระดับโลก วางไว้ในฟังก์ชันและเรียกใช้หลังจากการนำเข้าตามที่แนะนำในคำตอบที่ยอมรับแทน
jfs


3

ทำไมไม่เพียงแค่นำเข้า test1 สคริปต์ python ทุกตัวเป็นโมดูล วิธีที่ดีกว่าคือการมีฟังก์ชั่นเช่น main / run ใน test1.py, import test1 และ run 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 ในฐานะ subprocess ของ Python นั้นแทบไม่เคยเป็นทางออกที่ถูกต้องเลย หากคุณไปกับกระบวนการย่อยคุณควรหลีกเลี่ยงPopenหากฟังก์ชั่นระดับสูงไม่สามารถทำสิ่งที่คุณต้องการได้ ในกรณีนี้check_callหรือrunจะทำทุกสิ่งที่คุณต้องการและอื่น ๆ อีกมากโดยใช้การประปาน้อยลงในรหัสของคุณเอง
tripleee

0

กระบวนการนี้ค่อนข้างไม่เป็นออโธดอกซ์ แต่จะใช้ได้กับทุกเวอร์ชั่นของงูหลาม

สมมติว่าคุณต้องการรันสคริปต์ชื่อ 'recommend.py' ภายในเงื่อนไข 'if' จากนั้นใช้

if condition:
       import recommend

เทคนิคต่างกัน แต่ใช้งานได้!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.