In một dòng một cách linh hoạt


306

Tôi muốn thực hiện một số câu lệnh cung cấp đầu ra tiêu chuẩn mà không thấy dòng mới ở giữa các câu lệnh.

Cụ thể, giả sử tôi có:

for item in range(1,100):
    print item

Kết quả là:

1
2
3
4
.
.
.

Làm thế nào để điều này thay vì trông giống như:

1 2 3 4 5 ...

Thậm chí tốt hơn, có thể in một số duy nhất trên số cuối cùng, vì vậy chỉ có một số trên màn hình tại một thời điểm?


Câu trả lời:


482

Thay đổi print itemthành:

  • print item, trong Python 2.7
  • print(item, end=" ") trong Python 3

Nếu bạn muốn in dữ liệu động, hãy sử dụng cú pháp sau:

  • print(item, sep=' ', end='', flush=True) trong Python 3

Từ http://docs.python.org/reference/simple_stmts.html#print :> Một '\n'ký tự được viết ở cuối, trừ khi printcâu lệnh kết thúc bằng dấu phẩy. Đây là hành động duy nhất nếu câu lệnh chỉ chứa từ khóa print.
ewall

5
FYI: print (item, end = "") có thể được sử dụng trong Python2.7 bằng cách thêm 'từ print_feft' trong tương lai ở đầu tệp.
Hec

2
Nhưng flushkhông làm việc với from __future__ import print_functionkhông may.
Timmmm

@ewall nếu tôi đã làm print(item, end=", ")điều đó thì cũng thêm ,vào mục cuối cùng làm thế nào để ngăn chặn nó thêm ,vào mục cuối cùng
MarcoBianchi

@SamirTendulkar Nếu bạn đang sử dụng một vòng lặp for như câu hỏi ban đầu, bạn có thể tạo một trường hợp đặc biệt để xử lý mục cuối cùng trong danh sách một cách khác biệt ...
ewall

156

Nhân tiện ...... Làm thế nào để làm mới nó mỗi lần để nó in mi ở một nơi chỉ cần thay đổi số.

Nói chung, cách để làm điều đó là với các mã điều khiển đầu cuối . Đây là một trường hợp đặc biệt đơn giản, trong đó bạn chỉ cần một ký tự đặc biệt: U + 000D CARRIAGE RETURN, được viết bằng '\r'Python (và nhiều ngôn ngữ khác). Đây là một ví dụ hoàn chỉnh dựa trên mã của bạn:

from sys import stdout
from time import sleep
for i in range(1,20):
    stdout.write("\r%d" % i)
    stdout.flush()
    sleep(1)
stdout.write("\n") # move the cursor to the next line

Một số điều về điều này có thể gây ngạc nhiên:

  • Việc \rđi ở đầu chuỗi để trong khi chương trình đang chạy, con trỏ sẽ luôn ở sau số. Đây không chỉ là mỹ phẩm: một số trình giả lập thiết bị đầu cuối rất bối rối nếu bạn làm theo cách khác.
  • Nếu bạn không bao gồm dòng cuối cùng, thì sau khi chương trình kết thúc, trình bao của bạn sẽ in dấu nhắc của nó lên trên đầu số.
  • Điều stdout.flushnày là cần thiết trên một số hệ thống, hoặc bạn sẽ không nhận được bất kỳ đầu ra nào. Các hệ thống khác có thể không yêu cầu, nhưng nó không gây hại gì.

Nếu bạn thấy rằng điều này không hoạt động, điều đầu tiên bạn nên nghi ngờ là trình giả lập thiết bị đầu cuối của bạn bị lỗi. Các vttest chương trình có thể giúp bạn kiểm tra nó.

Bạn có thể thay thế stdout.writebằng một printcâu lệnh nhưng tôi không muốn trộn lẫn printvới việc sử dụng trực tiếp các đối tượng tệp.


Hàm meen flush () là gì? Trở thành nó làm việc cho tôi mà không có chức năng đó!
Pol

1
Thông thường, các đối tượng tệp của Python tích lũy dữ liệu để họ có thể gửi nó đến hệ điều hành theo từng khối lớn. Đây là những gì bạn muốn truy cập vào các tệp trên đĩa, thông thường, nhưng nó can thiệp vào loại nhiệm vụ này. flush()buộc một tập tin phải gửi bất cứ thứ gì nó có vào hệ điều hành ngay bây giờ. Tôi ngạc nhiên nó hoạt động cho bạn mà không có điều đó - nó đã không làm việc cho tôi cho đến khi tôi thêm nó.
zwol

1
@ user1995839 Có các mã điều khiển để ẩn con trỏ, nhưng nếu bạn định làm điều đó thì tôi khuyên bạn nên sử dụng ncursesđể làm điều đó.
zwol

1
sys.stdout.flush()dường như là sự thay đổi của tôi FreebsdvớiPython 2.7
Hakim

1
Lưu ý rằng lợi nhuận vận chuyển không hoạt động đúng trong REPL của Python (ít nhất là đối với tôi, trên Ubuntu); bạn cần phải thực thi một tập lệnh , không chỉ chạy lệnh REPL, để bất kỳ thứ nào trong số này hoạt động.
Đánh dấu Amery

50

Sử dụng print item,để làm cho câu lệnh in bỏ qua dòng mới.

Trong Python 3, nó print(item, end=" ").

Nếu bạn muốn mọi số hiển thị ở cùng một vị trí, hãy sử dụng ví dụ (Python 2.7):

to = 20
digits = len(str(to - 1))
delete = "\b" * (digits + 1)
for i in range(to):
    print "{0}{1:{2}}".format(delete, i, digits),

Trong Python 3, nó phức tạp hơn một chút; Ở đây bạn cần phải xả sys.stdouthoặc nó sẽ không in bất cứ thứ gì cho đến khi vòng lặp kết thúc:

import sys
to = 20
digits = len(str(to - 1))
delete = "\b" * (digits)
for i in range(to):
   print("{0}{1:{2}}".format(delete, i, digits), end="")
   sys.stdout.flush()

Trên thực tế, có vẻ như giải pháp của bạn sẽ in cùng một số lượng không gian. Vì vậy, nếu là 20, nó sẽ in thêm một khoảng lùi trong khi in các chữ số 1..9. Bạn không nên tính các chữ số bên trong vòng lặp và căn cứ vào giá trị của i?
Adam Crossland

Nó đúng - chỉ số và luôn xóa mọi thứ. Tôi đã không kiểm tra xem nó có nhanh hơn để làm điều đó hay để tính toán trong mỗi lần lặp lại có bao nhiêu chữ số sẽ bị xóa ngay bây giờ.
Tim Pietzcker

Hoặc, căn cứ vào giá trị trước đó của i để tính khi số chữ số thay đổi.
Adam Crossland

À, vâng, tôi đã nhìn quá mức biện minh. Giải pháp tốt.
Adam Crossland

Nghe có vẻ khá phức tạp. Tôi có lẽ sẽ không hiểu những gì tôi đã làm ở đó nếu tôi phải xem mã của tôi một năm kể từ bây giờ. (Chỉ cần đọc một chương trình tôi đã viết vào năm 2007 - Tôi rất vui vì tôi đã viết nó bằng Python.)
Tim Pietzcker

16

Giống như các ví dụ khác,
tôi sử dụng một cách tiếp cận tương tự nhưng thay vì dành thời gian để tính ra độ dài đầu ra cuối cùng, v.v.

Tôi chỉ đơn giản sử dụng mã thoát ANSI để quay trở lại đầu dòng và sau đó xóa toàn bộ dòng đó trước khi in đầu ra trạng thái hiện tại của tôi.

import sys

class Printer():
    """Print things to stdout on one line dynamically"""
    def __init__(self,data):
        sys.stdout.write("\r\x1b[K"+data.__str__())
        sys.stdout.flush()

Để sử dụng trong vòng lặp của bạn, bạn chỉ cần gọi một cái gì đó như:

x = 1
for f in fileList:
    ProcessFile(f)
    output = "File number %d completed." % x
    Printer(output)
    x += 1   

Xem thêm tại đây


14

Bạn có thể thêm dấu phẩy vào câu lệnh in của mình để in dấu cách thay vì dòng mới trong mỗi lần lặp:

print item,

Ngoài ra, nếu bạn đang sử dụng Python 2.6 trở lên, bạn có thể sử dụng chức năng in mới, điều này sẽ cho phép bạn chỉ định rằng thậm chí không gian sẽ xuất hiện ở cuối mỗi mục được in (hoặc cho phép bạn chỉ định bất kỳ kết thúc nào của bạn muốn):

from __future__ import print_function
...
print(item, end="")

Cuối cùng, bạn có thể ghi trực tiếp vào đầu ra tiêu chuẩn bằng cách nhập nó từ mô đun sys, trả về một đối tượng giống như tệp:

from sys import stdout
...
stdout.write( str(item) )

13

thay đổi

print item

đến

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" xóa đến cuối dòng
  • \ r, trở về đầu dòng
  • câu lệnh tuôn ra đảm bảo nó xuất hiện ngay lập tức để bạn có được đầu ra thời gian thực.

Điều này rất tốt cho Python 2.7. Bạn có thể cung cấp một tài liệu tham khảo đến nơi bạn đã học về \033[Kmã? Tôi muốn tìm hiểu thêm về họ.
Klik

printđã tuôn ra trong nội bộ. Không cần phải gọi nó. printkhác với sys.stdout.write()nơi bạn phải xuất hiện trên màn hình
Gabriel Fair

5

Tôi nghĩ rằng một tham gia đơn giản nên làm việc:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)

4
Một sự hiểu biết sẽ đọc tốt hơn và có thể được nhanh hơn : print ' '.join(str(x) for x in range(1, 10)).
Mu Tâm

Tôi thứ hai việc sử dụng một sự hiểu biết danh sách. Trong trường hợp này, nó sẽ làm cho nó dễ đọc hơn.
Austin Henley

5

Một câu trả lời khác mà tôi đang sử dụng trên 2.7 khi tôi chỉ in ra một "." mỗi khi một vòng lặp chạy (để cho người dùng biết rằng mọi thứ vẫn đang chạy) là:

print "\b.",

Nó in dấu "." các ký tự không có khoảng cách giữa mỗi. Nó trông tốt hơn một chút và hoạt động khá tốt. \ B là một ký tự backspace cho những người thắc mắc.


4

Rất nhiều câu trả lời phức tạp. Nếu bạn có python 3, chỉ cần đặt \rvào lúc bắt đầu in và thêm end='', flush=Truevào nó:

import time

for i in range(10):
    print(f'\r{i} foo bar', end='', flush=True)
    time.sleep(0.5)

Điều này sẽ viết 0 foo bar, sau đó 1 foo bar, tại chỗ.


Cảm ơn bạn, đó chỉ là những gì tôi cầnprint('\r' + filename + " ", end = '', flush=True)
McPeppr

3

Để làm cho các số ghi đè lên nhau, bạn có thể làm một cái gì đó như thế này:

for i in range(1,100):
    print "\r",i,

Điều đó sẽ làm việc miễn là số được in trong cột đầu tiên.

EDIT: Đây là phiên bản sẽ hoạt động ngay cả khi nó không được in trong cột đầu tiên.

prev_digits = -1
for i in range(0,1000):
    print("%s%d" % ("\b"*(prev_digits + 1), i)),
    prev_digits = len(str(i))

Tôi nên lưu ý rằng mã này đã được thử nghiệm và chỉ hoạt động tốt trong Python 2.5 trên Windows, trong bảng điều khiển WIndows. Theo một số người khác, có thể cần phải xả stdout để xem kết quả. YMMV.


3

"Nhân tiện ...... Làm thế nào để làm mới nó mỗi lần để nó in mi ở một nơi chỉ cần thay đổi số."

Đó thực sự là chủ đề khó khăn. Những gì zack đề xuất (xuất mã điều khiển bảng điều khiển) là một cách để đạt được điều đó.

Bạn có thể sử dụng (n) lời nguyền, nhưng hoạt động chủ yếu trên * nixes.

Trên Windows (và đây là phần thú vị) hiếm khi được đề cập (tôi không thể hiểu tại sao), bạn có thể sử dụng các ràng buộc Python để WinAPI ( http://sourceforge.net/projects/pywin32/ cũng với ActivePython theo mặc định) - không phải vậy chăm chỉ và làm việc tốt Đây là một ví dụ nhỏ:

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    output_handle.WriteConsoleOutputCharacter( i, pos )
    time.sleep( 1 )

Hoặc, nếu bạn muốn sử dụng print(câu lệnh hoặc hàm, không có sự khác biệt):

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    print i
    output_handle.SetConsoleCursorPosition( pos )
    time.sleep( 1 )

win32console mô-đun cho phép bạn thực hiện nhiều điều thú vị hơn với bảng điều khiển windows ... Tôi không phải là một fan hâm mộ lớn của WinAPI, nhưng gần đây tôi nhận ra rằng ít nhất một nửa ác cảm của tôi đối với nó là do viết mã WinAPI trong các ràng buộc C - pythonic dễ sử dụng hơn nhiều

Tất cả các câu trả lời khác là tuyệt vời và pythonic, tất nhiên, nhưng ... Nếu tôi muốn in trên dòng trước thì sao? Hoặc viết văn bản nhiều dòng, hơn là xóa nó và viết lại cùng một dòng? Giải pháp của tôi làm cho điều đó có thể.


2

cho Python 2.7

for x in range(0, 3):
    print x,

cho Python 3

for x in range(0, 3):
    print(x, end=" ")

1
In [9]: print?
Type:           builtin_function_or_method
Base Class:     <type 'builtin_function_or_method'>
String Form:    <built-in function print>
Namespace:      Python builtin
Docstring:
    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.

0

Nếu bạn chỉ muốn in các số, bạn có thể tránh vòng lặp.

# python 3
import time

startnumber = 1
endnumber = 100

# solution A without a for loop
start_time = time.clock()
m = map(str, range(startnumber, endnumber + 1))
print(' '.join(m))
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('took {0}ms\n'.format(timetaken))

# solution B: with a for loop
start_time = time.clock()
for i in range(startnumber, endnumber + 1):
    print(i, end=' ')
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('\ntook {0}ms\n'.format(timetaken))

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 mất 21.1986929975ms

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 mất 491.466823551ms


Nên nhanh hơn với việc hiểu danh sách thay vì map.
cji

Có ví dụ tốt. Tôi thích nó, nhưng tôi cần hiển thị kết quả của phân tích cú pháp. Đầu tiên tôi đếm các mục i cơ sở dữ liệu hơn in còn lại bao nhiêu.
Pol

0

Cách tốt nhất để thực hiện điều này là sử dụng \rnhân vật

Chỉ cần thử mã dưới đây:

import time
for n in range(500):
  print(n, end='\r')
  time.sleep(0.01)
print()  # start new line so most recently printed number stays

0

Trong Python 3 bạn có thể làm theo cách này:

for item in range(1,10):
    print(item, end =" ")

Đầu ra:

1 2 3 4 5 6 7 8 9 

Tuple: Bạn có thể làm điều tương tự với một tuple:

tup = (1,2,3,4,5)

for n in tup:
    print(n, end = " - ")

Đầu ra:

1 - 2 - 3 - 4 - 5 - 

Một vi dụ khac:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for item in list_of_tuples:
    print(item)

Đầu ra:

(1, 2)
('A', 'B')
(3, 4)
('Cat', 'Dog')

Bạn thậm chí có thể giải nén bộ dữ liệu của bạn như thế này:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]

# Tuple unpacking so that you can deal with elements inside of the tuple individually
for (item1, item2) in list_of_tuples:
    print(item1, item2)   

Đầu ra:

1 2
A B
3 4
Cat Dog

một biến thể khác:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for (item1, item2) in list_of_tuples:
    print(item1)
    print(item2)
    print('\n')

Đầu ra:

1
2


A
B


3
4


Cat
Dog

Tôi đã thử tất cả các ví dụ ở đây và không có công việc nào trong python 3.8 Vui lòng nhận thêm câu trả lời.
KOTZ

Tôi đã thử nghiệm nó với python 3.7
Stryker

Ý tôi là không có tùy chọn nào trong số các tùy chọn này ghi đè lên số cuối cùng giống như được đề xuất ở cuối câu hỏi.
KOTZ

0

Dấu phẩy ở cuối câu lệnh in bỏ qua dòng mới.

for i in xrange(1,100):
  print i,

nhưng điều này không ghi đè.


0

Đối với những người đấu tranh như tôi đã làm, tôi đã đưa ra những điều sau đây dường như hoạt động trong cả python 3.7.4 và 3.5.2.

Tôi đã mở rộng phạm vi từ 100 đến 1.000.000 vì nó chạy rất nhanh và bạn có thể không thấy đầu ra. Điều này là do một tác dụng phụ của cài đặt end='\r'là việc lặp vòng lặp cuối cùng sẽ xóa tất cả đầu ra. Một số dài hơn là cần thiết để chứng minh rằng nó hoạt động. Kết quả này có thể không được mong muốn trong mọi trường hợp, nhưng tôi vẫn ổn và OP không chỉ định cách này hay cách khác. Bạn có khả năng phá vỡ điều này bằng một câu lệnh if đánh giá độ dài của mảng được lặp lại, v.v. Chìa khóa để làm cho nó hoạt động trong trường hợp của tôi là ghép các dấu ngoặc "{}"với .format(). Mặt khác, nó đã không hoạt động.

Dưới đây nên làm việc như là:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)

0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Sản lượng: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, 50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74, 75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99


0

Hoặc thậm chí đơn giản hơn:

import time
a = 0
while True:
    print (a, end="\r")
    a += 1
    time.sleep(0.1)

end="\r" sẽ ghi đè từ đầu [0:] của bản in đầu tiên.

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.