Làm thế nào để tuôn ra đầu ra của chức năng in?


1216

Làm cách nào để buộc chức năng in của Python xuất ra màn hình?

Đây không phải là một bản sao của bộ đệm đầu ra Vô hiệu hóa - câu hỏi được liên kết đang cố gắng đầu ra không có bộ đệm , trong khi điều này là tổng quát hơn. Các câu trả lời hàng đầu trong câu hỏi đó quá mạnh mẽ hoặc liên quan đến câu hỏi này (chúng không phải là câu trả lời tốt cho câu hỏi này) và câu hỏi này có thể được tìm thấy trên Google bởi một người mới.

Câu trả lời:


1428

Trên Python 3, printcó thể lấy một flushđối số tùy chọn

print("Hello world!", flush=True)

Trên Python 2 bạn sẽ phải làm

import sys
sys.stdout.flush()

sau khi gọi print. Theo mặc định, printin ra sys.stdout(xem tài liệu để biết thêm về các đối tượng tệp ).


347

Đang chạy python -h, tôi thấy một tùy chọn dòng lệnh :

-u: stdout nhị phân không có bộ đệm và thiết bị xuất chuẩn; cũng PYTHONUNBUFFERED = x xem trang man để biết chi tiết về bộ đệm nội bộ liên quan đến '-u'

Đây là tài liệu có liên quan .


320

Kể từ Python 3.3, bạn có thể buộc print()hàm bình thường tuôn ra mà không cần sử dụng sys.stdout.flush(); chỉ cần đặt đối số từ khóa "tuôn" thành đúng. Từ tài liệu :

in (* đối tượng, sep = '', end = '\ n', file = sys.stdout, flush = Sai)

In các đối tượng vào tệp luồng, được phân tách bằng sep và theo sau là kết thúc. sep, end và file, nếu có, phải được đưa ra làm đối số từ khóa.

Tất cả các đối số không phải từ khóa được chuyển đổi thành các chuỗi như str () hiện và được ghi vào luồng, được phân tách bằng sep và theo sau là kết thúc. Cả sep và end phải là chuỗi; chúng cũng có thể là Không có nghĩa là sử dụng các giá trị mặc định. Nếu không có đối tượng nào được đưa ra, print () sẽ chỉ ghi kết thúc.

Đối số tệp phải là một đối tượng với phương thức write (chuỗi); nếu nó không có mặt hoặc Không có, sys.stdout sẽ được sử dụng. Cho dù đầu ra được đệm thường được xác định bởi tệp, nhưng nếu đối số từ khóa tuôn ra là đúng, luồng sẽ bị xóa.


198

Làm thế nào để tuôn ra đầu ra của Python in?

Tôi đề nghị năm cách để làm điều này:

  • Trong Python 3, gọi print(..., flush=True)(đối số tuôn ra không có sẵn trong chức năng in của Python 2 và không có tương tự cho câu lệnh in).
  • Gọi file.flush()tệp đầu ra (chúng ta có thể bọc chức năng in của python 2 để làm điều này), ví dụ:sys.stdout
  • áp dụng điều này cho mọi lệnh gọi chức năng in trong mô-đun với chức năng một phần,
    print = partial(print, flush=True)được áp dụng cho mô-đun toàn cầu.
  • áp dụng điều này cho quá trình với một cờ ( -u) được truyền cho lệnh phiên dịch
  • áp dụng điều này cho mọi quá trình python trong môi trường của bạn với PYTHONUNBUFFERED=TRUE(và bỏ đặt biến để hoàn tác điều này).

Python 3,3+

Sử dụng Python 3.3 trở lên, bạn chỉ có thể cung cấp flush=Truelàm đối số từ khóa cho printhàm:

print('foo', flush=True) 

Python 2 (hoặc <3.3)

Họ không đưa ra flushđối số cho Python 2.7 Vì vậy, nếu bạn đang sử dụng Python 2 (hoặc nhỏ hơn 3.3) và muốn mã tương thích với cả 2 và 3, tôi có thể đề xuất mã tương thích sau. (Lưu ý __future__nhập phải ở / rất "gần đầu mô-đun của bạn "):

from __future__ import print_function
import sys

if sys.version_info[:2] < (3, 3):
    old_print = print
    def print(*args, **kwargs):
        flush = kwargs.pop('flush', False)
        old_print(*args, **kwargs)
        if flush:
            file = kwargs.get('file', sys.stdout)
            # Why might file=None? IDK, but it works for print(i, file=None)
            file.flush() if file is not None else sys.stdout.flush()

Mã tương thích ở trên sẽ bao gồm hầu hết các sử dụng, nhưng để xử lý triệt để hơn nhiều, hãy xem sixmô-đun .

Ngoài ra, bạn chỉ có thể gọi file.flush()sau khi in, ví dụ, với câu lệnh in trong Python 2:

import sys
print 'delayed output'
sys.stdout.flush()

Thay đổi mặc định trong một mô-đun thành flush=True

Bạn có thể thay đổi mặc định cho chức năng in bằng cách sử dụng funcools.partial trên phạm vi toàn cầu của mô-đun:

import functools
print = functools.partial(print, flush=True)

nếu bạn nhìn vào hàm một phần mới của chúng tôi, ít nhất là trong Python 3:

>>> print = functools.partial(print, flush=True)
>>> print
functools.partial(<built-in function print>, flush=True)

Chúng ta có thể thấy nó hoạt động giống như bình thường:

>>> print('foo')
foo

Và chúng ta thực sự có thể ghi đè mặc định mới:

>>> print('foo', flush=False)
foo

Lưu ý một lần nữa, điều này chỉ thay đổi phạm vi toàn cầu hiện tại, vì tên in trên phạm vi toàn cầu hiện tại sẽ làm lu mờ printchức năng dựng sẵn (hoặc bỏ qua chức năng tương thích, nếu sử dụng một trong Python 2, trong phạm vi toàn cầu hiện tại đó).

Nếu bạn muốn thực hiện điều này bên trong một hàm thay vì trên phạm vi toàn cầu của mô-đun, bạn nên đặt cho nó một tên khác, ví dụ:

def foo():
    printf = functools.partial(print, flush=True)
    printf('print stuff like this')

Nếu bạn khai báo nó là một hàm toàn cục, bạn đang thay đổi nó trên không gian tên toàn cầu của mô-đun, vì vậy bạn chỉ nên đặt nó trong không gian tên toàn cầu, trừ khi hành vi cụ thể đó là chính xác những gì bạn muốn.

Thay đổi mặc định cho quá trình

Tôi nghĩ rằng lựa chọn tốt nhất ở đây là sử dụng -ucờ để có được đầu ra không có bộ đệm.

$ python -u script.py

hoặc là

$ python -um package.module

Từ các tài liệu :

Buộc stdin, stdout và stderr phải hoàn toàn không có bộ đệm. Trên các hệ thống có vấn đề, cũng đặt stdin, stdout và stderr ở chế độ nhị phân.

Lưu ý rằng có bộ đệm nội bộ trong file.readlines () và Đối tượng tệp (đối với dòng trong sys.stdin) không bị ảnh hưởng bởi tùy chọn này. Để giải quyết vấn đề này, bạn sẽ muốn sử dụng file.readline () trong vòng lặp 1:.

Thay đổi mặc định cho môi trường vận hành shell

Bạn có thể có hành vi này cho tất cả các quy trình python trong môi trường hoặc môi trường kế thừa từ môi trường nếu bạn đặt biến môi trường thành một chuỗi không trống:

ví dụ: trong Linux hoặc OSX:

$ export PYTHONUNBUFFERED=TRUE

hoặc Windows:

C:\SET PYTHONUNBUFFERED=TRUE

từ các tài liệu :

PYTHONUNBUFFERED

Nếu điều này được đặt thành một chuỗi không trống, nó tương đương với việc chỉ định tùy chọn -u.


Phụ lục

Đây là trợ giúp về chức năng in từ Python 2.7.12 - lưu ý rằng không có flush đối số:

>>> from __future__ import print_function
>>> help(print)
print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout)

    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file: a file-like object (stream); defaults to the current sys.stdout.
    sep:  string inserted between values, default a space.
    end:  string appended after the last value, default a newline.

Đối với việc di chuyển tò mò từ các phiên bản Python thấp hơn: __future__phiên bản không bao gồm flushvì "đối số tuôn ra đã được thêm vào Python 3.3 (sau khi in () được nhập vào 2.7 thông qua quá trình nhập trong tương lai)" bug.python.org/su28458
Oliver

69

Cũng như được đề xuất trong blog này, người ta có thể mở lại sys.stdoutở chế độ không có bộ đệm:

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Mỗi stdout.writeprinthoạt động sẽ được tự động xả sau đó.


2
Trên Ubuntu 12.04 trong python 2.7, điều này mang lại cho tôiUnsupportedOperation: IOStream has no fileno.
drevicko

3
Rất tiếc, Python 3 đã tìm ra. Nó sẽ không cho phép tôi thực thi đoạn mã này!
EKons

Tôi bối rối bởi thành ngữ này. Sau khi bạn làm điều này, bây giờ không có hai đối tượng giống như Tệp (sys.stdout ban đầu và sys.stdout mới) mà cả hai đều nghĩ rằng họ "sở hữu" fileno? Điều đó thật tệ phải không?
Don nở

62

Với Python 3.x, print()chức năng đã được mở rộng:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Vì vậy, bạn chỉ có thể làm:

print("Visiting toilet", flush=True)

Nhập tài liệu Python


36

Sử dụng -ucông tắc dòng lệnh hoạt động, nhưng nó hơi vụng về. Điều đó có nghĩa là chương trình có khả năng hành xử không chính xác nếu người dùng gọi tập lệnh mà không có -utùy chọn. Tôi thường sử dụng một tùy chỉnh stdout, như thế này:

class flushfile:
  def __init__(self, f):
    self.f = f

  def write(self, x):
    self.f.write(x)
    self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

... Bây giờ tất cả các printcuộc gọi của bạn (sử dụng sys.stdoutngầm), sẽ được tự động chỉnh sửa flush.


4
Tôi khuyên bạn không nên kế thừa từ tệp và sau đó ủy quyền cho thiết bị xuất chuẩn bằng cách thêm. def __getattr__(self,name): return object.__getattribute__(self.f, name)
deaththreetimes

2
Nếu không có những thay đổi được đề xuất bởi nhận xét của @diedthreetimes, tôi nhận được "ValueError: Thao tác I / O trên tệp đã đóng"
blueFast

19

Tại sao không thử sử dụng một tập tin không có bộ đệm?

f = open('xyz.log', 'a', 0)

HOẶC LÀ

sys.stdout = open('out.log', 'a', 0)

1
Anh ta không muốn ot tạo một tập tin không có bộ đệm; anh ta muốn làm cho thiết bị xuất chuẩn hiện tại (được chuyển hướng đến bàn điều khiển, thiết bị đầu cuối hoặc bất cứ điều gì: không được thay đổi).
blueFast

13

Ý tưởng của Dan không hoàn toàn hiệu quả:

#!/usr/bin/env python
class flushfile(file):
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

print "foo"

Kết quả:

Traceback (most recent call last):
  File "./passpersist.py", line 12, in <module>
    print "foo"
ValueError: I/O operation on closed file

Tôi tin rằng vấn đề là nó kế thừa từ lớp tập tin, điều thực sự không cần thiết. Theo các tài liệu cho sys.stdout:

stdout và stderr không cần phải là các đối tượng tệp dựng sẵn: bất kỳ đối tượng nào cũng được chấp nhận miễn là nó có phương thức write () nhận đối số chuỗi.

quá thay đổi

class flushfile(file):

đến

class flushfile(object):

làm cho nó hoạt động tốt


17
Không bỏ phiếu vì giải pháp này của IS @ Dan ... (Bạn nên bình luận bài đăng của Dan thay vì sao chép giải pháp của anh ấy)
gecco

8

Đây là phiên bản của tôi, cung cấp cả danh sách ghi () và fileno ():

class FlushFile(object):
    def __init__(self, fd):
        self.fd = fd

    def write(self, x):
        ret = self.fd.write(x)
        self.fd.flush()
        return ret

    def writelines(self, lines):
        ret = self.writelines(lines)
        self.fd.flush()
        return ret

    def flush(self):
        return self.fd.flush

    def close(self):
        return self.fd.close()

    def fileno(self):
        return self.fd.fileno()

Giải pháp ưu việt. Và nó hoạt động. Đã thử nghiệm trên Python 3.4.0. Với các phiên bản khác, xuất phát từ file, tôi gặp lỗi. Không có filelớp học.
Colin D Bennett

6

Trong Python 3, bạn có thể ghi đè chức năng in với mặc định được đặt thành flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)

2
câu trả lời này có vẻ hơi nhẹ với tất cả các phản hồi chất lượng cao khác. bạn có thể muốn thêm một chút nữa cho nó.
Dấu chấm phẩy và băng keo trong

5

Tôi đã làm nó như thế này trong Python 3.4:

'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end="")
message('I am flushing out now...')

2

Trước tiên tôi phải vật lộn để hiểu làm thế nào các tùy chọn tuôn ra hoạt động. Tôi muốn thực hiện một 'màn hình tải' và đây là giải pháp tôi tìm thấy:

for i in range(100000):
    print('{:s}\r'.format(''), end='', flush=True)
    print('Loading index: {:d}/100000'.format(i+1), end='')

Dòng đầu tiên tuôn ra bản in trước và dòng thứ hai in một thông báo cập nhật mới. Tôi không biết nếu một cú pháp một dòng tồn tại ở đây.

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.