Apa cara terbaik untuk memanggil skrip dari skrip lain?

307

Saya memiliki skrip bernama test1.py yang tidak ada dalam modul. Itu hanya memiliki kode yang harus dijalankan ketika skrip itu sendiri dijalankan. Tidak ada fungsi, kelas, metode, dll. Saya punya skrip lain yang berjalan sebagai layanan. Saya ingin memanggil test1.py dari skrip yang menjalankan sebagai layanan.

Sebagai contoh:

File test1.py

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

File service.py

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

Saya mengetahui satu metode yang membuka file, membaca konten, dan pada dasarnya mengevaluasi itu. Saya berasumsi ada cara yang lebih baik untuk melakukan ini. Atau setidaknya saya harap begitu.

Josh Smeaton
sumber
42
Cara yang lebih baik adalah menulis metode dan kelas dan menggunakannya
Aamir
3
Belum ada yang mengirim runpy.run_modulejawaban ?!
Aran-Fey

Jawaban:

279

Cara biasa untuk melakukan ini adalah seperti berikut ini.

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()
ars
sumber
44
Bagaimana jika test1.pyterletak di direktori yang jauh?
Evgeni Sergeev
3
@EvgeniSergeev Lihat stackoverflow.com/questions/67631/…
Evgeni Sergeev
18
Ini tidak benar-benar menjawab pertanyaan, bukan? Anda tidak menjalankan keseluruhan skrip, Anda menjalankan beberapa fungsi dari dalam skrip yang Anda impor.
gented
2
@GennaroTedesco: Anda salah. The import test1dalam service.pymemang menjalankan seluruh naskah (yang hanya mendefinisikan some_func()sejak __name__ == '__main__'akan Falsedalam kasus itu). Kedengarannya seperti semua OP ingin lakukan. Jawaban ini melampaui itu, tetapi jelas menjawab pertanyaan — dan kemudian beberapa.
martineau
2
Jika, katakanlah, test1.pytidak mengandung definisi fungsi some_func()(melainkan hanya beberapa baris kode, misalnya print("hello")) maka kode Anda tidak akan berfungsi. Dalam contoh khusus ini tidak berfungsi karena pada dasarnya Anda mengimpor fungsi eksternal yang kemudian Anda panggil kembali.
gented
144

Ini dimungkinkan menggunakan Python 2

execfile("test2.py")

Lihat dokumentasi untuk penanganan ruang nama, jika penting dalam kasus Anda.

Dalam Python 3, ini dimungkinkan menggunakan (terima kasih kepada @fantastory)

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

Namun, Anda harus mempertimbangkan untuk menggunakan pendekatan yang berbeda; ide Anda (dari apa yang bisa saya lihat) tidak terlihat sangat bersih.

balpha
sumber
9
langsung apa yang saya butuhkan di python 32 itu adalah exec (open ('test2.py'). read ())
fantastory
8
Pendekatan ini mengeksekusi skrip di dalam namespace panggilan. :)
dmvianna
6
untuk meneruskan argumen baris perintah ke skrip, Anda dapat mengedit sys.argvdaftar.
jfs
1
Perlakuan yang lebih komprehensif pada setara Python 3: stackoverflow.com/questions/436198/…
John Y
2
Ini tidak menerima argumen (untuk diteruskan ke file PY)!
Apostolos
70

Cara lain:

File test1.py:

print "test1.py"

File service.py:

import subprocess

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

Keuntungan dari metode ini adalah Anda tidak perlu mengedit skrip Python yang ada untuk meletakkan semua kodenya ke dalam subrutin.

Dokumentasi: Python 2 , Python 3

Dick Goodwin
sumber
7
Saya harus menggunakannya subprocess.call("./test1.py", shell=True)untuk membuatnya bekerja
asmaier
5
Jangan gunakan shell=Truekecuali itu perlu.
Piotr Dobrogost
2
@PiotrDobrogost - Bisakah Anda menentukan situasi mana yang membuatnya perlu?
sancho.s ReinstateMonicaCellio
7
Ini tidak akan bekerja pada Unix yang khas di mana direktori saat ini tidak di PATH. test1.pyharus dapat dieksekusi dan memiliki garis shebang ( #!/usr/bin/env python) dan Anda harus menentukan path lengkap atau Anda harus menyediakan sendiri executable: di call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])mana get_script_dir()didefinisikan di sini .
JFS
5
Atau subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Jika Anda ingin test1.py tetap dapat dieksekusi dengan fungsi yang sama seperti ketika dipanggil di dalam service.py, maka lakukan sesuatu seperti:

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
Michael Schneider
sumber
3
Bagaimana jika Anda memiliki parameter runtime?
Gabriel Fair
13
import os

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

Menggunakan os, Anda dapat melakukan panggilan langsung ke terminal Anda. Jika Anda ingin lebih spesifik, Anda dapat menggabungkan string input Anda dengan variabel lokal, yaitu.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Alex Mapley
sumber
panggilan ke os.systemharus dihindari, Anda dapat melakukan hal yang sama dengan Kelas apa saja dariPopen, Call,
user1767754
Dari dokumentasi Python : Modul subproses menyediakan fasilitas yang lebih kuat untuk memunculkan proses baru dan mengambil hasilnya; menggunakan modul itu lebih baik daripada menggunakan fungsi ini.
Big McLargeHuge
12

Anda seharusnya tidak melakukan ini. Sebaliknya, lakukan:

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()
thedz
sumber
1
ketika Anda mengimpor test1 bagaimana ia tahu di mana file itu? apakah harus di direktori yang sama? bagaimana jika tidak?
NULL. Bung
8

Gunakan import test1untuk penggunaan pertama - ini akan menjalankan skrip. Untuk pemanggilan selanjutnya, perlakukan skrip sebagai modul yang diimpor, dan panggil reload(test1)metode tersebut.

Kapan reload(module)dieksekusi:

  • Kode modul Python dikompilasi ulang dan kode tingkat modul dieksekusi kembali , mendefinisikan seperangkat objek baru yang terikat pada nama-nama dalam kamus modul. Fungsi init dari modul ekstensi tidak disebut

Pemeriksaan sederhana sys.modulesdapat digunakan untuk menjalankan tindakan yang sesuai. Untuk terus merujuk ke nama skrip sebagai string ( 'test1'), gunakan builtin ' impor ()' .

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
Gimel
sumber
3
reloadhilang dalam Python 3.
Piotr Dobrogost
1
mengimpor modul tidak sama dengan menjalankannya, mis. pertimbangkan if __name__ == "__main__":penjaga. Mungkin ada perbedaan lain yang lebih halus. Jangan tinggalkan kode arbitrer di tingkat global. Masukkan ke dalam fungsi dan menyebutnya setelah impor seperti yang disarankan dalam jawaban yang diterima bukan
JFS
5

Saya lebih suka 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')
Flavio
sumber
3

Mengapa tidak mengimpor test1 saja? Setiap skrip python adalah modul. Cara yang lebih baik adalah dengan memiliki fungsi misalnya main / run di test1.py, impor test1 dan jalankan test1.main (). Atau Anda dapat menjalankan test1.py sebagai subproses.

Anurag Uniyal
sumber
3

Seperti yang sudah disebutkan, runpycara yang bagus untuk menjalankan skrip atau modul lain dari skrip saat ini.

Ngomong-ngomong, sangat umum bagi pelacak atau debugger untuk melakukan ini, dan dalam keadaan seperti itu metode seperti mengimpor file secara langsung atau menjalankan file dalam subproses biasanya tidak berfungsi.

Itu juga perlu perhatian untuk digunakan execuntuk menjalankan kode. Anda harus menyediakan yang tepat run_globalsuntuk menghindari kesalahan impor atau beberapa masalah lainnya. Lihat runpy._run_codedetailnya.

Chao Chen
sumber
0

Ini adalah contoh dengan subprocessperpustakaan:

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_)
Benyamin Jafari
sumber
1
Menjalankan Python sebagai subproses dari Python hampir tidak pernah merupakan solusi yang tepat. Jika Anda menggunakan subproses, Anda harus menghindari Popenkecuali fungsi tingkat yang lebih tinggi benar-benar tidak dapat melakukan apa yang Anda inginkan. Dalam hal ini, check_callatau runakan melakukan semua yang Anda butuhkan dan banyak lagi, dengan jumlah pipa yang lebih sedikit dalam kode Anda sendiri.
tripleee
0

Proses ini agak tidak ortodoks, tetapi akan bekerja di semua versi python,

Misalkan Anda ingin menjalankan skrip bernama 'recommend.py' di dalam kondisi 'jika', lalu gunakan,

if condition:
       import recommend

Tekniknya berbeda, tetapi berhasil!

Ashwin Balani
sumber