Saya mencoba memahami apa motivasi di balik penggunaan fungsi pustaka Python untuk menjalankan tugas-tugas spesifik OS seperti membuat file / direktori, mengubah atribut file, dll. Daripada hanya menjalankan perintah-perintah itu melalui os.system()
atau subprocess.call()
?
Misalnya, mengapa saya ingin menggunakan os.chmod
daripada melakukan os.system("chmod...")
?
Saya mengerti bahwa lebih "pythonic" untuk menggunakan metode pustaka Python yang tersedia sebanyak mungkin daripada hanya menjalankan perintah shell secara langsung. Tetapi, adakah motivasi lain di balik melakukan hal ini dari sudut pandang fungsionalitas?
Saya hanya berbicara tentang mengeksekusi perintah shell satu baris sederhana di sini. Ketika kita membutuhkan lebih banyak kontrol atas pelaksanaan tugas, saya mengerti bahwa menggunakan subprocess
modul lebih masuk akal, misalnya.
sumber
print
bisa begituos.system("echo Hello world!")
?os.path
untuk menangani jalur alih-alih menanganinya secara manual: ini bekerja pada setiap OS di mana ia berjalan.os.chmod
tidak akan memanggilchmod
program yang akan dibuat oleh shell. Menggunakanos.system('chmod ...')
meluncurkan shell untuk menafsirkan string untuk memanggil lain executable untuk membuat panggilan ke Cchmod
fungsi, sementaraos.chmod(...)
berjalan jauh lebih langsung ke Cchmod
.Jawaban:
Ini lebih cepat ,
os.system
dansubprocess.call
membuat proses baru yang tidak perlu untuk sesuatu yang sederhana ini. Bahkan,os.system
dansubprocess.call
denganshell
argumen biasanya membuat setidaknya dua proses baru: yang pertama adalah shell, dan yang kedua adalah perintah yang Anda jalankan (jika itu bukan shell built-in liketest
).Beberapa perintah tidak berguna dalam proses terpisah . Misalnya, jika Anda menjalankan
os.spawn("cd dir/")
, itu akan mengubah direktori kerja saat ini dari proses anak, tetapi tidak dari proses Python. Anda perlu menggunakannyaos.chdir
untuk itu.Anda tidak perlu khawatir tentang karakter khusus yang ditafsirkan oleh shell.
os.chmod(path, mode)
akan bekerja tidak peduli apa nama file itu, sedangkanos.spawn("chmod 777 " + path)
akan gagal total jika nama file itu seperti; rm -rf ~
. (Perhatikan bahwa Anda dapat mengatasi ini jika Anda menggunakansubprocess.call
tanpashell
argumen.)Anda tidak perlu khawatir tentang nama file yang dimulai dengan tanda hubung .
os.chmod("--quiet", mode)
akan mengubah izin file bernama--quiet
, tetapios.spawn("chmod 777 --quiet")
akan gagal, sebagaimana--quiet
ditafsirkan sebagai argumen. Ini berlaku bahkan untuksubprocess.call(["chmod", "777", "--quiet"])
.Anda memiliki lebih sedikit masalah lintas-platform dan lintas-shell, karena perpustakaan standar Python seharusnya menangani itu untuk Anda. Apakah sistem Anda memiliki
chmod
perintah? Apakah sudah diinstal? Apakah itu mendukung parameter yang Anda harapkan didukung? Theos
modul akan mencoba untuk menjadi seperti cross-platform mungkin dan dokumen ketika bahwa itu tidak mungkin.Jika perintah yang Anda jalankan memiliki keluaran yang Anda pedulikan, Anda perlu menguraikannya, yang lebih sulit daripada kedengarannya, karena Anda mungkin melupakan kasus sudut (nama file dengan spasi, tab, dan baris baru di dalamnya), bahkan ketika Anda tidak peduli tentang portabilitas.
sumber
ls
ataudir
tingkat yang cukup tinggi untuk jenis pengembang tertentu, sama sepertibash
ataucmd
atauksh
atau apa pun shell yang Anda inginkan.ls
lebih tinggi dari itu, karena ini bukan panggilan langsung ke API kernel OS Anda. Ini adalah aplikasi (kecil).ls
ataudir
tetapiopendir()/readdir()
(linux api) atauFindFirstFile()/FindNextFile()
(windows api) atauFile.listFiles
(java API) atauDirectory.GetFiles()
(C #). Semua ini terkait erat dengan panggilan langsung ke OS. Beberapa mungkin sesederhana memasukkan nomor ke dalam register dan memanggilint 13h
untuk memicu mode kernel.Itu lebih aman. Untuk memberi Anda ide di sini adalah contoh skrip
Jika input dari pengguna adalah
test; rm -rf ~
ini maka akan menghapus direktori home.Inilah sebabnya mengapa lebih aman untuk menggunakan fungsi bawaan.
Karenanya mengapa Anda harus menggunakan subproses alih-alih sistem juga.
sumber
Ada empat kasus kuat untuk memilih metode Python yang lebih spesifik dalam
os
modul daripada menggunakanos.system
atausubprocess
modul saat menjalankan perintah:os
modul ini tersedia di berbagai platform sementara banyak perintah shell bersifat spesifik-os.os
modul.Redundansi (lihat kode redundan ):
Anda sebenarnya mengeksekusi "perantara" yang berlebihan dalam perjalanan Anda ke panggilan sistem yang akhirnya (
chmod
dalam contoh Anda). Orang tengah ini adalah proses atau sub-shell baru.Dari
os.system
:Dan
subprocess
hanya sebuah modul untuk menelurkan proses baru.Anda dapat melakukan apa yang Anda butuhkan tanpa memunculkan proses ini.
Portabilitas (lihat kode sumber portabilitas ):
Tujuan
os
modul adalah untuk menyediakan layanan sistem operasi generik dan uraiannya dimulai dengan:Anda dapat menggunakan
os.listdir
kedua windows dan unix. Mencoba menggunakanos.system
/subprocess
untuk fungsi ini akan memaksa Anda untuk mempertahankan dua panggilan (untukls
/dir
) dan memeriksa sistem operasi yang Anda gunakan . Ini tidak portabel dan akan menyebabkan frustrasi lebih banyak di kemudian hari (lihat Menangani Penanganan ).Memahami hasil perintah:
Misalkan Anda ingin membuat daftar file dalam direktori.
Jika Anda menggunakan
os.system("ls")
/subprocess.call(['ls'])
, Anda hanya bisa mendapatkan kembali proses, yang pada dasarnya adalah string besar dengan nama file.Bagaimana Anda bisa memberi tahu file dengan spasi di namanya dari dua file?
Bagaimana jika Anda tidak memiliki izin untuk mendaftarkan file?
Bagaimana seharusnya Anda memetakan data ke objek python?
Ini hanya di atas kepala saya, dan sementara ada solusi untuk masalah ini - mengapa memecahkan lagi masalah yang dipecahkan untuk Anda?
Ini adalah contoh mengikuti prinsip Don't Repeat Yourself (Sering disebut sebagai "KERING") dengan tidak mengulangi implementasi yang sudah ada dan tersedia secara bebas untuk Anda.
Keamanan:
os.system
dansubprocess
sangat kuat. Itu bagus ketika Anda membutuhkan kekuatan ini, tetapi itu berbahaya ketika Anda tidak. Ketika Anda menggunakanos.listdir
, Anda tahu itu tidak bisa melakukan hal lain selain daftar file atau meningkatkan kesalahan. Ketika Anda menggunakanos.system
atausubprocess
untuk mencapai perilaku yang sama, Anda berpotensi berakhir melakukan sesuatu yang tidak Anda inginkan.Keselamatan Injeksi (lihat contoh injeksi shell ) :
Jika Anda menggunakan input dari pengguna sebagai perintah baru, pada dasarnya Anda memberinya shell. Ini seperti injeksi SQL yang menyediakan shell di DB untuk pengguna.
Contohnya adalah perintah dari formulir:
Ini dapat dengan mudah dieksploitasi untuk menjalankan kode arbitrer apa pun menggunakan input:
NASTY COMMAND;#
untuk membuat akhirnya:Ada banyak perintah yang dapat membahayakan sistem Anda.
sumber
Untuk alasan sederhana - ketika Anda memanggil fungsi shell, itu membuat sub-shell yang dihancurkan setelah perintah Anda ada, jadi jika Anda mengubah direktori di shell - itu tidak mempengaruhi lingkungan Anda di Python.
Selain itu, membuat sub-shell memakan waktu, jadi menggunakan perintah OS secara langsung akan berdampak pada kinerja Anda
EDIT
Saya menjalankan beberapa tes waktu:
Fungsi internal berjalan lebih dari 10 kali lebih cepat
EDIT2
Mungkin ada kasus ketika menjalankan executable eksternal dapat menghasilkan hasil yang lebih baik daripada paket Python - Saya baru ingat sebuah surat yang dikirim oleh seorang rekan saya bahwa kinerja gzip yang dipanggil melalui subproses jauh lebih tinggi daripada kinerja paket Python yang ia gunakan. Tetapi tentu saja tidak ketika kita berbicara tentang paket OS standar meniru perintah OS standar
sumber
%
menggunakan juru bahasa normal.time <path to script>
terminal dan itu akan memberi tahu Anda waktu yang sebenarnya, pengguna dan proses yang diambil. Itu jika Anda tidak memiliki iPython dan Anda memiliki akses ke baris perintah Unix.Panggilan Shell bersifat spesifik OS sedangkan fungsi modul os Python tidak, dalam sebagian besar kasus. Dan itu menghindari menelurkan subproses.
sumber
Jauh lebih efisien. "Shell" hanyalah binari OS lain yang berisi banyak panggilan sistem. Mengapa harus mengeluarkan biaya untuk membuat seluruh proses shell hanya untuk pemanggilan sistem tunggal?
Situasinya bahkan lebih buruk ketika Anda menggunakan
os.system
sesuatu yang bukan shell. Anda memulai proses shell yang pada gilirannya memulai executable yang kemudian (dua proses jauhnya) membuat panggilan sistem. Setidaknyasubprocess
akan menghilangkan kebutuhan untuk proses perantara shell.Ini tidak spesifik untuk Python, ini.
systemd
adalah peningkatan waktu startup Linux untuk alasan yang sama: itu membuat sistem yang diperlukan memanggil dirinya sendiri bukannya menelurkan seribu shell.sumber