Sự khác biệt giữa quy trình con Popen và cuộc gọi (làm thế nào tôi có thể sử dụng chúng)?


178

Tôi muốn gọi một chương trình bên ngoài từ Python. Tôi đã sử dụng cả hai Popen()call()để làm điều đó.

Sự khác biệt giữa hai là gì?

Mục tiêu cụ thể của tôi là chạy lệnh sau từ Python. Tôi không chắc chắn làm thế nào chuyển hướng làm việc.

./my_script.sh > output

Tôi đọc tài liệu và nó nói rằng đó call()là chức năng tiện lợi hoặc chức năng phím tắt. Chúng ta có mất sức mạnh bằng cách sử dụng call()thay vì Popen()?


Phần nào của tài liệu làm bạn bối rối? Định nghĩa của call()dường như là rất rõ ràng. Bạn có thể cung cấp một trích dẫn hoặc một liên kết để chúng tôi biết những gì cần tập trung vào một câu trả lời?
S.Lott

Câu trả lời:


265

Có hai cách để thực hiện chuyển hướng. Cả hai áp dụng đối với một trong hai subprocess.Popenhoặc subprocess.call.

  1. Đặt đối số từ khóa shell = Truehoặc executable = /path/to/the/shellvà chỉ định lệnh giống như bạn có nó ở đó.

  2. Vì bạn chỉ chuyển hướng đầu ra thành một tệp, hãy đặt đối số từ khóa

    stdout = an_open_writeable_file_object

    trong đó đối tượng trỏ đến outputtập tin.

subprocess.Popenlà tổng quát hơn subprocess.call.

Popenkhông chặn, cho phép bạn tương tác với quy trình trong khi nó đang chạy hoặc tiếp tục với những thứ khác trong chương trình Python của bạn. Cuộc gọi để Popentrả về một Popenđối tượng.

call không chặn. Mặc dù nó hỗ trợ tất cả các đối số giống như hàm Popentạo, vì vậy bạn vẫn có thể đặt đầu ra của quy trình, biến môi trường, v.v., tập lệnh của bạn chờ chương trình hoàn tất và calltrả về mã đại diện cho trạng thái thoát của quy trình.

returncode = call(*args, **kwargs) 

về cơ bản giống như gọi

returncode = Popen(*args, **kwargs).wait()

callchỉ là một chức năng tiện lợi. Việc triển khai trong CPython là trong quy trình con :

def call(*popenargs, timeout=None, **kwargs):
    """Run command with arguments.  Wait for command to complete or
    timeout, then return the returncode attribute.

    The arguments are the same as for the Popen constructor.  Example:

    retcode = call(["ls", "-l"])
    """
    with Popen(*popenargs, **kwargs) as p:
        try:
            return p.wait(timeout=timeout)
        except:
            p.kill()
            p.wait()
            raise

Như bạn có thể thấy, đó là một lớp bọc mỏng xung quanh Popen.


17
Về cơ bản Popen và cuộc gọi là các hàm không đồng bộ và đồng bộ tương ứng được sử dụng chạy các lệnh Linux.
dùng606020

1
Lợi thế của việc sử dụng popen là gì? Sẽ không an toàn khi đợi cho đến khi chương trình được gọi kết thúc trước?
Tom

4
@Tom Thường thì không. Điều gì sẽ xảy ra nếu bạn muốn đọc một số đầu ra, sau đó gửi thêm đầu vào cho chương trình, đọc thêm đầu ra mà kết quả từ đầu vào đó, lặp lại?
agf

@ user3016020 Tôi giả sử điều này cũng áp dụng cho các lệnh Windows? Đúng?
domih

7

Câu trả lời khác là rất đầy đủ, nhưng đây là một quy tắc:

  • call đang chặn:

    call('notepad.exe')
    print('hello')  # only executed when notepad is closed
  • Popen là không chặn:

    Popen('notepad.exe')
    print('hello')  # immediately executed
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.