Cách sử dụng quy trình con để chạy các chương trình bên ngoài trong Python 3
Python 3 bao gồm mô-đun quysubprocess
để chạy các chương trình bên ngoài và đọc kết quả kết quả của chúng bằng mã Python của bạn. Bạn có thể thấy quy subprocess
hữu ích nếu bạn muốn sử dụng một chương trình khác trên máy tính của bạn từ trong mã Python của bạn. Ví dụ: bạn có thể cần gọi git
từ trong mã Python của bạn để truy xuất các file trong dự án của bạn được theo dõi trong kiểm soát version git
. Vì bất kỳ chương trình nào bạn có thể truy cập trên máy tính của bạn đều có thể được điều khiển bởi quy subprocess
, các ví dụ được hiển thị ở đây sẽ có thể áp dụng cho bất kỳ chương trình bên ngoài nào bạn có thể cần gọi từ mã Python của bạn .
subprocess
bao gồm một số lớp học và chức năng, nhưng trong hướng dẫn này ta sẽ giới thiệu một trong những subprocess
của các chức năng hữu ích nhất: subprocess.run
. Ta sẽ xem xét các cách sử dụng khác nhau và các đối số từ khóa chính của nó.
Yêu cầu
Để tận dụng tối đa hướng dẫn này, bạn nên làm quen với lập trình bằng Python 3. Bạn có thể xem lại các hướng dẫn này để biết thông tin cơ bản cần thiết:
Chạy một chương trình bên ngoài
Bạn có thể sử dụng hàm subprocess.run
để chạy chương trình bên ngoài từ mã Python của bạn . Tuy nhiên, trước tiên, bạn cần nhập quy subprocess
và module sys
vào chương trình của bạn :
import subprocess import sys result = subprocess.run([sys.executable, "-c", "print('ocean')"])
Nếu bạn chạy điều này, bạn sẽ nhận được kết quả như sau:
Outputocean
Hãy xem lại ví dụ này:
-
sys.executable
là đường dẫn tuyệt đối đến file thực thi Python mà chương trình của bạn ban đầu được gọi. Ví dụ:sys.executable
có thể là một đường dẫn như/usr/local/bin/python
. -
subprocess.run
được cung cấp một danh sách các chuỗi bao gồm các thành phần của lệnh mà ta đang cố gắng chạy. Vì chuỗi đầu tiên ta truyền làsys.executable
, ta đang hướng dẫnsubprocess.run
thực thi một chương trình Python mới. - Thành phần
-c
là một tùy chọn dòng lệnhpython
cho phép bạn truyền một chuỗi với toàn bộ chương trình Python để thực thi. Trong trường hợp của ta , ta truyền một chương trình in raocean
chuỗi.
Bạn có thể coi mỗi mục nhập trong danh sách mà ta chuyển đến subprocess.run
như được phân tách bằng dấu cách. Ví dụ: [sys.executable, "-c", "print('ocean')"]
dịch gần đúng thành /usr/local/bin/python -c "print('ocean')"
. Lưu ý quy subprocess
tự động trích dẫn các thành phần của lệnh trước khi cố gắng chạy chúng trên hệ điều hành cơ bản để ví dụ: bạn có thể chuyển một tên file có khoảng trắng trong đó.
Cảnh báo: Không bao giờ chuyển đầu vào không tin cậy cho subprocess.run
. Vì subprocess.run
có khả năng thực hiện các lệnh tùy ý trên máy tính của bạn, các tác nhân độc hại có thể sử dụng nó để thao túng máy tính của bạn theo những cách không mong muốn.
Bắt kết quả từ một chương trình bên ngoài
Bây giờ ta có thể gọi một chương trình bên ngoài bằng cách sử dụng subprocess.run
, hãy xem cách ta có thể nắm bắt kết quả từ chương trình đó. Ví dụ: quá trình này có thể hữu ích nếu ta muốn sử dụng git ls-files
để xuất tất cả các file của bạn hiện được lưu trữ dưới sự kiểm soát của version .
Lưu ý: Các ví dụ hiển thị trong phần này yêu cầu Python 3.7 hoặc cao hơn. Đặc biệt, các đối số từ khóa capture_output
và text
đã được thêm vào trong Python 3.7 khi nó được phát hành vào tháng 6 năm 2018.
Hãy thêm vào ví dụ trước của ta :
import subprocess import sys result = subprocess.run( [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True ) print("stdout:", result.stdout) print("stderr:", result.stderr)
Nếu ta chạy mã này, ta sẽ nhận được kết quả như sau:
Outputstdout: ocean stderr:
Ví dụ này phần lớn giống với ví dụ được giới thiệu trong phần đầu tiên: ta vẫn đang chạy một quy trình con để in ocean
. Tuy nhiên, điều quan trọng là ta chuyển các đối số từ khóa capture_output=True
và text=True
vào subprocess.run
.
subprocess.run
trả về một đối tượng subprocess.CompletedProcess
được ràng buộc với result
. Đối tượng subprocess.CompletedProcess
bao gồm các chi tiết về mã thoát của chương trình bên ngoài và kết quả của nó. capture_output=True
đảm bảo result.stdout
và result.stderr
được điền bằng kết quả tương ứng từ chương trình bên ngoài. Theo mặc định, result.stdout
và result.stderr
được ràng buộc dưới dạng byte, nhưng đối số từ khóa text=True
hướng dẫn Python thay vào đó giải mã các byte thành chuỗi.
Trong phần kết quả , stdout
là ocean
(cộng với dòng mới ở cuối print
thêm ẩn) và ta không có stderr
.
Hãy thử một ví dụ tạo ra một giá trị không trống cho stderr
:
import subprocess import sys result = subprocess.run( [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True ) print("stdout:", result.stdout) print("stderr:", result.stderr)
Nếu ta chạy mã này, ta nhận được kết quả như sau:
Outputstdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops
Mã này chạy một quy trình con Python ngay lập tức tạo ra một ValueError
. Khi ta kiểm tra kết result
cuối cùng, ta không thấy gì trong stdout
và một Traceback
của ValueError
trong stderr
. Điều này là do theo mặc định, Python viết Traceback
của ngoại lệ chưa được xử lý vào stderr
.
Nâng cao một ngoại lệ trên một mã thoát xấu
Đôi khi, rất hữu ích khi nêu ra một ngoại lệ nếu một chương trình ta chạy thoát với mã thoát không hợp lệ. Các chương trình thoát với mã 0 được coi là thành công, nhưng các chương trình thoát với mã khác 0 được coi là đã gặp lỗi. Ví dụ: mẫu này có thể hữu ích nếu ta muốn đưa ra một ngoại lệ trong trường hợp ta chạy git ls-files
trong một folder thực sự không phải là repository git
.
Ta có thể sử dụng đối số từ khóa check=True
cho subprocess.run
để có một ngoại lệ được đưa ra nếu chương trình bên ngoài trả về mã thoát khác 0:
import subprocess import sys result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
Nếu ta chạy mã này, ta nhận được kết quả như sau:
OutputTraceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.
Kết quả này cho thấy rằng ta đã chạy một quy trình con gây ra lỗi, quy trình này được in bằng stderr
trong terminal của ta . Sau đó, subprocess.run
đã đưa ra một quy subprocess.CalledProcessError
thay mặt ta trong chương trình Python chính của ta .
Ngoài ra, module quy subprocess
cũng bao gồm phương thức subprocess.CompletedProcess.check_returncode
, mà ta có thể gọi để có hiệu ứng tương tự:
import subprocess import sys result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"]) result.check_returncode()
Nếu ta chạy mã này, ta sẽ nhận được:
OutputTraceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.
Vì ta không chuyển check=True
cho subprocess.run
, ta đã liên kết thành công một cá thể subprocess.CompletedProcess
để result
đến result
mặc dù chương trình của ta đã thoát với mã khác 0. Tuy nhiên, việc gọi result.check_returncode()
sẽ tạo ra một quy subprocess.CalledProcessError
vì nó phát hiện quá trình đã hoàn thành được thoát ra bằng một mã không hợp lệ.
Sử dụng thời gian chờ để thoát khỏi chương trình sớm
subprocess.run
bao gồm đối số timeout
để cho phép bạn dừng một chương trình bên ngoài nếu mất quá nhiều thời gian để thực thi:
import subprocess import sys result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
Nếu ta chạy mã này, ta sẽ nhận được kết quả như sau:
OutputTraceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds
Quá trình con mà ta cố gắng chạy đã sử dụng chức năng time.sleep
để ngủ trong 2
giây. Tuy nhiên, ta đã chuyển đối số từ khóa timeout=1
cho subprocess.run
để hết thời gian xử lý con sau 1
giây. Điều này giải thích lý do tại sao lệnh gọi subprocess.run
của ta cuối cùng lại tạo ra một ngoại lệ subprocess.TimeoutExpired
.
Lưu ý đối số từ khóa timeout
cho subprocess.run
là gần đúng. Python sẽ cố gắng hết sức để giết quá trình con sau số giây timeout
, nhưng nó không nhất thiết phải chính xác.
Chuyển đầu vào cho các chương trình
Đôi khi các chương trình mong đợi đầu vào được chuyển cho chúng qua stdin
.
Đối số từ khóa input
cho subprocess.run
cho phép bạn truyền dữ liệu vào stdin
của quy trình con. Ví dụ:
import subprocess import sys result = subprocess.run( [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater" )
Ta sẽ nhận được kết quả như sau sau khi chạy mã này:
Outputunderwater
Trong trường hợp này, ta chuyển các byte underwater
input
. Quy trình con mục tiêu của ta đã sử dụng sys.stdin
để đọc nội dung được truyền trong stdin
( underwater
) và in nó ra trong kết quả của ta .
Đối số từ khóa input
có thể hữu ích nếu bạn muốn xâu chuỗi nhiều lệnh gọi subprocess.run
lại với nhau để chuyển kết quả của một chương trình làm đầu vào cho chương trình khác.
Kết luận
Mô-đun quy subprocess
là một phần mạnh mẽ của thư viện chuẩn Python cho phép bạn chạy các chương trình bên ngoài và kiểm tra kết quả của chúng một cách dễ dàng. Trong hướng dẫn này, bạn đã học cách sử dụng subprocess.run
để điều khiển các chương trình bên ngoài, chuyển đầu vào cho chúng, phân tích cú pháp kết quả của chúng và kiểm tra mã trả về của chúng.
Mô-đun quy subprocess
hiển thị các lớp và tiện ích bổ sung mà ta chưa đề cập trong hướng dẫn này. Đến đây bạn đã có đường cơ sở, bạn có thể sử dụng tài liệu của module quy subprocess
để tìm hiểu thêm về các lớp và tiện ích có sẵn khác.
Các tin liên quan
Làm thế nào để đánh lừa một mạng neural trong Python 32020-07-30
Cách sử dụng hàm bộ lọc Python
2020-07-24
Cách sử dụng module pathlib để thao tác đường dẫn hệ thống tệp trong Python 3
2020-07-15
Cách tạo Slackbot bằng Python trên Ubuntu 20.04
2020-06-30
Cách sử dụng ThreadPoolExecutor trong Python 3
2020-06-23
Cách sử dụng module sqlite3 trong Python 3
2020-06-02
Cách thiết lập notebook Jupyter với Python 3 trên Ubuntu 20.04 và Kết nối qua Đường hầm SSH
2020-05-19
Cách cài đặt Phân phối Python Anaconda trên Ubuntu 20.04 [Khởi động nhanh]
2020-05-19
Cách cài đặt Phân phối Python Anaconda trên Ubuntu 20.04
2020-05-06
Cách cài đặt Python 3 và thiết lập môi trường lập trình trên server Ubuntu 20.04
2020-04-24