Cách tốt nhất để gọi một kịch bản từ một kịch bản khác là gì?


307

Tôi có một tập lệnh có tên test1.py không có trong một mô-đun. Nó chỉ có mã nên thực thi khi tập lệnh được chạy. Không có chức năng, lớp, phương thức, v.v. Tôi có một đoạn script khác chạy dưới dạng dịch vụ. Tôi muốn gọi test1.py từ tập lệnh đang chạy như một dịch vụ.

Ví dụ:

Tệp test1.py

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

Tập tin dịch vụ

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

Tôi biết một phương pháp đang mở tệp, đọc nội dung và về cơ bản là đánh giá nó. Tôi cho rằng có một cách tốt hơn để làm điều này. Hoặc ít nhất tôi hy vọng như vậy.


42
Cách tốt hơn là viết các phương thức và các lớp và sử dụng chúng
Aamir


3
Chưa có ai đăng runpy.run_modulecâu trả lời?!
Aran-Fey

Câu trả lời:


279

Cách thông thường để làm điều này là một cái gì đó như sau.

test1.py

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

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

dịch vụ

import test1

def service_func():
    print 'service func'

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

44
Điều gì nếu test1.pynằm trong một số thư mục xa?
Evgeni Sergeev


18
Điều này không thực sự trả lời câu hỏi, phải không? Bạn không thực thi toàn bộ tập lệnh, bạn đang thực thi một số chức năng từ bên trong tập lệnh mà bạn nhập.
gạc

2
@GennaroTedesco: Bạn đang nhầm. Các import test1trong service.pykhông thực sự thực hiện toàn bộ kịch bản (mà chỉ xác định some_func()từ năm __name__ == '__main__'sẽ là Falsetrong trường hợp đó). Nghe có vẻ như tất cả các OP muốn làm. Câu trả lời này vượt xa điều đó, nhưng chắc chắn không trả lời được câu hỏi và sau đó là một số câu hỏi.
martineau

2
Nếu, giả sử, test1.pykhông chứa định nghĩa của hàm some_func()(ví dụ, chỉ là một số dòng mã print("hello")) thì mã của bạn sẽ không hoạt động. Trong ví dụ cụ thể này, nó hoạt động được vì về cơ bản bạn đang nhập một chức năng bên ngoài mà sau đó bạn sẽ gọi lại.
gents

144

Điều này có thể có trong Python 2 bằng cách sử dụng

execfile("test2.py")

Xem tài liệu để xử lý các không gian tên, nếu quan trọng trong trường hợp của bạn.

Trong Python 3, điều này có thể sử dụng (nhờ @fantastory)

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

Tuy nhiên, bạn nên xem xét sử dụng một cách tiếp cận khác; ý tưởng của bạn (từ những gì tôi có thể thấy) không có vẻ rất sạch sẽ.


9
trực tiếp những gì tôi cần trong python 32 đó là exec (open ('test2.py'). read ())
fantastory

8
Cách tiếp cận này thực thi các tập lệnh trong không gian tên gọi. :)
dmvianna

6
để chuyển các đối số dòng lệnh vào tập lệnh, bạn có thể chỉnh sửa sys.argvdanh sách.
JFS

1
Điều trị toàn diện hơn trên tương đương Python 3: stackoverflow.com/questions/436198/ cấp
John Y

2
Điều này không chấp nhận đối số (sẽ được chuyển đến tệp PY)!
Apostolos

70

Cách khác:

Tệp test1.py:

print "test1.py"

Tập tin dịch vụ:

import subprocess

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

Ưu điểm của phương pháp này là bạn không phải chỉnh sửa tập lệnh Python hiện có để đưa tất cả mã của nó vào chương trình con.

Tài liệu: Python 2 , Python 3


7
Tôi đã phải sử dụng subprocess.call("./test1.py", shell=True)để làm cho nó hoạt động
asmaier

5
Không sử dụng shell=Truetrừ khi nó cần thiết.
Piotr Dobrogost

2
@PiotrDobrogost - Bạn có thể chỉ định những tình huống nào sẽ khiến nó cần thiết không?
sancho.s RebstateMonicaCellio 26/12/13

7
Nó sẽ không hoạt động trên một Unix điển hình trong đó thư mục hiện tại không có trong PATH. test1.pynên được thực thi và có dòng shebang ( #!/usr/bin/env python) và bạn nên chỉ định đường dẫn đầy đủ hoặc bạn cần tự cung cấp tệp thực thi: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])nơi get_script_dir()được xác định ở đây .
JFS

5
Hoặc subprocess.call(['python', 'test1.py']).
Big McLUNDHuge

21

Nếu bạn muốn test1.py vẫn có thể thực thi được với cùng chức năng như khi nó được gọi bên trong service.py, thì hãy làm một cái gì đó như:

test1.py

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

if __name__ == "__main__":
    main()

dịch vụ

import test1
# lots of stuff here
test1.main() # do whatever is in test1.py

3
Nếu bạn có các tham số thời gian chạy thì sao?
Hội chợ Gabriel

13
import os

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

Sử dụng os bạn có thể thực hiện cuộc gọi trực tiếp đến thiết bị đầu cuối của bạn. Nếu bạn muốn cụ thể hơn nữa, bạn có thể nối chuỗi đầu vào của mình với các biến cục bộ, tức là.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)

os.systemnên tránh các cuộc gọi , bạn có thể thực hiện tương tự với bất kỳ Lớp nào từPopen, Call,
user1767754

Từ tài liệu Python : Mô-đun quy trình con cung cấp các phương tiện mạnh hơn để sinh ra các quy trình mới và lấy kết quả của chúng; sử dụng mô-đun đó là tốt hơn để sử dụng chức năng này.
Big McLUNDHuge

12

Bạn không nên làm điều này. Thay vào đó, hãy làm:

test1.py:

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

dịch vụ

#near the top
from test1 import print_test
#lots of stuff here
print_test()

1
Khi bạn nhập test1, làm thế nào để biết tệp đó ở đâu? nó có phải nằm trong cùng một thư mục không? Nếu không phải thì sao?
NULL.Dude

8

Sử dụng import test1cho lần sử dụng đầu tiên - nó sẽ thực thi tập lệnh. Đối với các yêu cầu sau này, hãy coi tập lệnh như một mô-đun đã nhập và gọi reload(test1)phương thức.

Khi reload(module)được thực thi:

  • Mã của mô-đun Python được biên dịch lại và mã cấp mô-đun được kiểm tra lại , xác định một bộ đối tượng mới được liên kết với tên trong từ điển của mô-đun. Hàm init của các module mở rộng không được gọi

Một kiểm tra đơn giản sys.modulescó thể được sử dụng để gọi hành động thích hợp. Để tiếp tục đề cập đến tên tập lệnh dưới dạng chuỗi ( 'test1'), hãy sử dụng nội dung ' nhập ()' .

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

3
reloadđã biến mất trong Python 3.
Piotr Dobrogost

1
nhập một mô-đun không tương đương với việc chạy nó, ví dụ, xem xét if __name__ == "__main__":bảo vệ. Có thể có sự khác biệt tinh tế hơn. Đừng để mã tùy ý ở cấp độ toàn cầu. Đặt nó vào một hàm và gọi nó sau khi nhập như được đề xuất trong câu trả lời được chấp nhận thay vào đó
jfs

5

Tôi thích runpy :

#!/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

Tại sao không chỉ nhập test1? Mỗi kịch bản python là một mô-đun. Cách tốt hơn là có một hàm, ví dụ: main / run trong test1.py, nhập test1 và chạy test1.main (). Hoặc bạn có thể thực thi test1.py như một quy trình con.


3

Như đã đề cập, đây runpylà một cách hay để chạy các tập lệnh hoặc mô-đun khác từ tập lệnh hiện tại.

Nhân tiện, một trình theo dõi hoặc trình gỡ lỗi khá phổ biến để thực hiện việc này và trong các trường hợp như vậy, các phương thức như nhập tệp trực tiếp hoặc chạy tệp trong quy trình con thường không hoạt động.

Nó cũng cần chú ý để sử dụng execđể chạy mã. Bạn phải cung cấp đúng run_globalsđể tránh lỗi nhập hoặc một số vấn đề khác. Tham khảo để runpy._run_codebiết chi tiết.


0

Đây là một ví dụ với subprocessthư viện:

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
Chạy Python như một quy trình con của Python gần như không bao giờ là giải pháp chính xác. Nếu bạn đi với một quy trình con, bạn nên tránh Popentrừ khi các hàm cấp cao hơn thực sự không thể làm những gì bạn muốn. Trong trường hợp này, check_callhoặc runsẽ làm mọi thứ bạn cần và hơn thế nữa, với hệ thống ống nước ít hơn đáng kể trong mã của riêng bạn.
tripleee

0

Quá trình này có phần không chính thống, nhưng sẽ hoạt động trên tất cả các phiên bản python,

Giả sử bạn muốn thực thi một tập lệnh có tên 'recomm.py' trong điều kiện 'nếu', sau đó sử dụng,

if condition:
       import recommend

Kỹ thuật là khác nhau, nhưng hoạt động!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.