Câu hỏi Làm thế nào để bạn đọc từ stdin trong Python?


Tôi đang cố gắng làm một số mã golf thách thức, nhưng tất cả đều đòi hỏi đầu vào phải được lấy từ stdin. Làm thế nào để có được điều đó trong Python?


1174
2017-09-20 05:48


gốc




Các câu trả lời:


Bạn có thể sử dụng fileinput module:

import fileinput

for line in fileinput.input():
    pass

fileinput sẽ lặp qua tất cả các dòng trong đầu vào được chỉ định dưới dạng tên tệp được đưa ra trong các đối số dòng lệnh hoặc đầu vào tiêu chuẩn nếu không có đối số nào được cung cấp.


804
2017-09-20 05:53





Có một vài cách để làm điều đó.

  • sys.stdin là một đối tượng giống như tệp mà bạn có thể gọi hàm read hoặc là readlines nếu bạn muốn đọc tất cả mọi thứ hoặc bạn muốn đọc tất cả mọi thứ và chia nó bằng dòng mới tự động. (Bạn cần phải import sys để làm việc này.)

  • Nếu bạn muốn lời nhắc người dùng cho đầu vào, bạn có thể sử dụng raw_input trong Python 2.X và chỉ input trong Python 3.

  • Nếu bạn thực sự chỉ muốn đọc các tùy chọn dòng lệnh, bạn có thể truy cập chúng thông qua sys.argv danh sách.

Có thể bạn sẽ tìm thấy bài viết Wikibook này về I / O bằng Python là một tham chiếu hữu ích.


585
2017-07-20 10:30





import sys

for line in sys.stdin:
    print line

333
2018-03-03 19:05



Đây là câu trả lời chính xác. - thepure12
Lưu ý rằng điều này sẽ bao gồm ký tự dòng mới ở cuối - brittohalloran
Để xóa dòng mới ở cuối, hãy sử dụng line.rstrip() - brittohalloran
Tôi đồng ý. Đây là câu trả lời chính xác. - Teekin


Python cũng có các hàm dựng sẵn input() và raw_input(). Xem tài liệu Python dưới Chức năng tích hợp sẵn.

Ví dụ,

name = raw_input("Enter your name: ")   # Python 2.x

hoặc là

name = input("Enter your name: ")   # Python 3

180
2017-09-30 09:08



Điều này đọc một dòng, mà không thực sự là những gì OP hỏi về. Tôi giải thích câu hỏi là "làm thế nào để đọc một loạt các dòng từ một xử lý tập tin mở cho đến khi EOF?" - tripleee
OP không yêu cầu đọc đầu vào từ bàn phím, anh ấy yêu cầu đọc từ stdin trong tình huống cuộc thi thường được cung cấp cho các thí sinh. - chrisfs


Đây là từ Học Python:

import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."

Trên Unix, bạn có thể kiểm tra nó bằng cách làm một cái gì đó như:

% cat countlines.py | python countlines.py 
Counted 3 lines.

Trên Windows hoặc DOS, bạn sẽ làm:

C:\> type countlines.py | python countlines.py 
Counted 3 lines.

160
2017-07-30 04:10



Đây là cách hiệu quả hơn (và có thể nhanh hơn) để đếm các dòng trong Python: print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), ''))). xem wc-l.py - jfs
Việc sử dụng cat đây là dư thừa. Lời gọi chính xác cho các hệ thống Unix là python countlines.py < countlines.py. - istepaniuk
"Học Python" là sai trong việc hướng người dùng sử dụng readlines(). Các đối tượng tệp được dự định sẽ được lặp lại mà không cần phải thực hiện tất cả dữ liệu trong bộ nhớ. - Aaron Hall♦


Câu trả lời do người khác đề xuất:

for line in sys.stdin:
  print line

là rất đơn giản và pythonic, nhưng nó phải được lưu ý rằng kịch bản sẽ đợi cho đến khi EOF trước khi bắt đầu lặp lại trên dòng đầu vào.

Điều này có nghĩa rằng tail -f error_log | myscript.py sẽ không xử lý các dòng như mong đợi.

Kịch bản lệnh chính xác cho trường hợp sử dụng như vậy sẽ là:

while 1:
    try:
        line = sys.stdin.readline()
    except KeyboardInterrupt:
        break

    if not line:
        break

    print line

CẬP NHẬT
Từ các ý kiến ​​nó đã được xóa rằng trên trăn 2 chỉ có thể có đệm liên quan, do đó bạn sẽ kết thúc chờ đợi cho bộ đệm để điền vào hoặc EOF trước khi cuộc gọi in được ban hành.


85
2017-08-09 16:31



Các for line in sys.stdin: mẫu không làm đợi EOF. Nhưng nếu bạn thử nghiệm trên các tệp rất nhỏ, các phản hồi có thể bị giật. Thử nghiệm với nhiều dữ liệu hơn để thấy rằng nó đọc kết quả trung gian. - mb.
Tôi chờ đợi cho End Of File hoặc đệm, khi lấy đầu vào từ một dòng khi sử dụng python 2.6.6, nhưng với 3.1.3 tôi không. chú thích print line không thức dậy trong 3.1.3, nhưng print(line) làm. - ctrl-alt-delor
python của tôi 2.7.5 "cho dòng trong sys.stdin", khối cho đến khi EOF hoặc một số lượng hợp lý của dữ liệu đã đệm. Tốt để xử lý luồng. Không tốt cho việc xử lý dòng hoặc đầu vào của người dùng. - Sean
Tôi nghi ngờ điều này liên quan đến phát hiện tty trong libc, vì vậy khi bạn phát hiện nó trên một vỏ tương tác, nó phát hiện không có tty, unbuffer từ mong đợi-dev là một tiện dụng util mà tôi tin rằng tiêm một shim qua ld_preload để is_atty trả về true (I nghi ngờ đó là cách nó đang bàn giao nó) - Mâtt Frëëman
@Sean: sai rồi. for line in sys.stdin: không "chặn cho đến EOF". Đây là một lỗi đọc trước trong Python 2 làm trễ các dòng cho đến khi vùng đệm tương ứng đầy. Đây là vấn đề đệm không liên quan đến EOF. Để giải quyết sự cố, hãy sử dụng for line in iter(sys.stdin.readline, ''): (sử dụng io.open() cho các tệp thông thường). Bạn không cần nó trong Python 3. - jfs


Làm thế nào để bạn đọc từ stdin trong Python?

Tôi đang cố gắng thực hiện một số thách thức về mã golf, nhưng tất cả đều yêu cầu đầu vào được lấy từ stdin. Làm thế nào để có được điều đó trong Python?

Bạn có thể dùng:

  • sys.stdin - Một đối tượng giống như tập tin sys.stdin.read() để đọc mọi thứ.
  • input(prompt) - chuyển cho nó một dấu nhắc tùy chọn để xuất, nó đọc từ stdin lên đến dòng mới đầu tiên, mà nó sẽ cắt. Bạn sẽ phải làm điều này nhiều lần để có được nhiều dòng hơn, ở phần cuối của đầu vào nó làm tăng EOFError. (Có lẽ là không tuyệt vời cho chơi golf.) Trong Python 2, đây là rawinput(prompt).
  • open(0).read() - Trong Python 3 open chấp nhận tập tin mô tả (số nguyên đại diện cho tài nguyên hệ điều hành IO) và 0 là bộ mô tả của stdin. Nó trả về một đối tượng giống như tệp sys.stdin - có lẽ là đặt cược tốt nhất của bạn để chơi gôn.
  • open('/dev/stdin').read() - tương tự như open(0), hoạt động trên Python 2 và 3, nhưng không hoạt động trên Windows (hoặc thậm chí Cygwin).
  • fileinput.input() - trả về một trình lặp trên các dòng trong tất cả các tệp được liệt kê trong sys.argv[1:], hoặc stdin nếu không được đưa ra. Sử dụng như ''.join(fileinput.input()).

Cả hai sys và fileinput phải được nhập khẩu, tương ứng, tất nhiên.

Nhanh chóng sys.stdin ví dụ tương thích với Python 2 và 3, Windows, Unix

Bạn chỉ cần read từ sys.stdin, ví dụ, nếu bạn nhập dữ liệu vào stdin:

$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo

ví dụ tệp

Giả sử bạn có một tệp, inputs.txt, chúng tôi có thể chấp nhận tệp đó và viết lại:

python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt

Câu trả lời dài hơn

Đây là bản demo hoàn chỉnh, dễ dàng sao chép, sử dụng hai phương pháp, hàm dựng sẵn, input (sử dụng raw_input trong Python 2), và sys.stdin. Dữ liệu chưa được sửa đổi, do đó quá trình xử lý không hoạt động.

Để bắt đầu, hãy tạo một tệp cho đầu vào:

$ python -c "print('foo\nbar\nbaz')" > inputs.txt

Và sử dụng mã mà chúng ta đã thấy, chúng ta có thể kiểm tra xem chúng ta đã tạo tệp chưa:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt 
foo
bar
baz

Đây là trợ giúp về sys.stdin.read từ Python 3:

read(size=-1, /) method of _io.TextIOWrapper instance
    Read at most n characters from stream.

    Read from underlying buffer until we have n characters or we hit EOF.
    If n is negative or omitted, read until EOF.

Hàm Builtin, input (raw_input trong Python 2)

Hàm dựng sẵn input đọc từ đầu vào tiêu chuẩn lên đến một dòng mới, được tước (bổ sung print, điều này cho biết thêm một dòng mới theo mặc định.) Điều này xảy ra cho đến khi nó được EOF (End Of File), tại thời điểm đó nó tăng EOFError.

Vì vậy, đây là cách bạn có thể sử dụng input bằng Python 3 (hoặc raw_input trong Python 2) để đọc từ stdin - vì vậy chúng ta tạo ra một mô-đun Python, chúng ta gọi stdindemo.py:

$ python -c "print('try:\n    while True:\n        print(input())\nexcept EOFError:\n    pass')" > stdindemo.py 

Và chúng ta hãy in nó ra để đảm bảo nó như chúng ta mong đợi:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py 
try:
    while True:
        print(input())
except EOFError:
    pass

Lần nữa, input đọc lên cho đến khi dòng mới và về cơ bản dải nó từ dòng. print thêm một dòng mới. Vì vậy, trong khi cả hai sửa đổi đầu vào, sửa đổi của họ hủy bỏ. (Vì vậy, chúng chủ yếu là bổ sung của nhau.)

Và khi input nhận được ký tự cuối tập tin, nó làm tăng EOFError, mà chúng ta bỏ qua và sau đó thoát khỏi chương trình.

Và trên Linux / Unix, chúng ta có thể lấy từ con mèo:

$ cat inputs.txt | python -m stdindemo
foo
bar
baz

Hoặc chúng ta chỉ có thể chuyển hướng tệp từ stdin:

$ python -m stdindemo < inputs.txt 
foo
bar
baz

Chúng tôi cũng có thể thực thi mô-đun dưới dạng tập lệnh:

$ python stdindemo.py < inputs.txt 
foo
bar
baz

Đây là sự trợ giúp về nội trang input từ Python 3:

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.

    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.

    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

sys.stdin

Ở đây chúng ta tạo một kịch bản demo bằng cách sử dụng sys.stdin. Cách hiệu quả để lặp qua một đối tượng giống như tệp là sử dụng đối tượng giống như tệp làm trình lặp. Phương pháp bổ sung để ghi vào stdout từ đầu vào này đơn giản là sử dụng sys.stdout.write:

$ python -c "print('import sys\nfor line in sys.stdin:\n    sys.stdout.write(line)')" > stdindemo2.py

In lại để đảm bảo có vẻ đúng:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py 
import sys
for line in sys.stdin:
    sys.stdout.write(line)

Và chuyển hướng các đầu vào vào tệp:

$ python -m stdindemo2 < inputs.txt
foo
bar
baz

Chơi gôn thành một mệnh lệnh:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz

Trình mô tả tệp cho chơi gôn

Kể từ khi mô tả tập tin cho stdin và stdout lần lượt là 0 và 1, chúng tôi cũng có thể chuyển open trong Python 3 (không phải 2, và lưu ý rằng chúng ta vẫn cần 'w' để viết thành stdout).

Nếu điều này làm việc trên hệ thống của bạn, nó sẽ cạo bỏ nhiều ký tự hơn.

$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo

Python 2's io.open thực hiện điều này là tốt, nhưng quá trình nhập chiếm nhiều không gian hơn:

$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt 
foo
bar
baz

Giải quyết các nhận xét và câu trả lời khác

Một nhận xét gợi ý ''.join(sys.stdin) nhưng thực sự dài hơn sys.stdin.read () - cộng với Python phải tạo một danh sách bổ sung trong bộ nhớ (đó là cách str.join hoạt động khi không được cung cấp danh sách) - để đối chiếu:

''.join(sys.stdin)
sys.stdin.read()

Câu trả lời hàng đầu cho thấy:

import fileinput

for line in fileinput.input():
    pass

Nhưng kể từ khi sys.stdin triển khai API tệp, bao gồm giao thức trình lặp, điều đó giống như sau:

import sys

for line in sys.stdin:
    pass

Câu trả lời khác làm đề nghị điều này. Chỉ cần nhớ rằng nếu bạn làm điều đó trong một thông dịch viên, bạn sẽ cần phải làm Ctrl- -d nếu bạn đang sử dụng Linux hoặc Mac hoặc Ctrl- -z trên Windows (sau Đi vào) để gửi ký tự cuối tập tin cho quá trình. Ngoài ra, câu trả lời đó gợi ý print(line) - thêm một '\n' đến cùng - sử dụng print(line, end='') thay vào đó (nếu trong Python 2, bạn sẽ cần from __future__ import print_function).

Trường hợp sử dụng thực sự cho fileinput là để đọc trong một loạt các tập tin.


49
2017-07-29 15:04