如何让Python 3的Print适应命令提示符的大小?

4

Python 3可以轻松处理大量文本的打印:

text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vitae odio quis felis consectetur blandit. Etiam mattis vehicula ex id sodales. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris fermentum semper nisi vel aliquam. Ut nec facilisis lectus. Maecenas auctor blandit condimentum. Donec finibus orci ac imperdiet congue. Pellentesque sem leo, commodo non metus ac, posuere maximus lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. "
print(text)

问题在于这段文字被打印成这样:

enter image description here

。这显然对文本的可读性不利。手动浏览所有文本并插入空白行相当麻烦。我看到了这个问题,但我想知道是否有自动执行此操作的选项。

2
你尝试过使用 https://docs.python.org/3/library/pprint.html 或者 https://docs.python.org/3/library/textwrap.html 吗? - jonrsharpe
3个回答

7
如评论所述,pprinttextwrap可用于调整输出到给定宽度。因此,唯一的诀窍是确定要使用的宽度。您可以使用78或80并假设窗口大小为这么大,但这意味着如果终端较小,则会出现错误的换行,如果终端较大,则会浪费空间。
要检查与pprint/textwrap配合使用的实际宽度(如果您使用的是Python 3.3或更高版本),则可以使用shutil.get_terminal_size
import shutil

def get_terminal_columns():
    return shutil.get_terminal_size().columns

如果您无法使用3.3+版本,您可以使用 curses模块以稍微复杂的方式确定大小:
import curses

def get_terminal_columns():
    try:
        # Initialize curses for terminal and check dimensions
        rows, cols = curses.initscr().getmaxyx()
    finally:
        # Unload curses to release control of terminal so it behaves normally
        curses.endwin()
    return cols

使用其中一个函数,您可以定义:
from __future__ import print_function  # Only needed on Py2
import textwrap

def print_autobreak(*args, sep=' '):
    width = get_terminal_columns()  # Check size once to avoid rechecks per "paragraph"
    # Convert all args to strings, join with separator, then split on any newlines,
    # preserving line endings, so each "paragraph" wrapped separately
    for line in sep.join(map(str, args)).splitlines(True):
        # Py3's print function makes it easy to print textwrap.wrap's result as one-liner
        print(*textwrap.wrap(line, width), sep="\n")

这个功能会根据终端大小自动在单词之间进行换行,保留已有的“硬”换行和空格,并(部分)匹配print的行为,允许多个参数和可选分隔符。在打印之前需要完全实现输出字符串(原始的print可以逐个打印,对于大量输出减少了内存使用),但这是执行适当的全局包装的副作用。
如果您需要更完整的换行处理(因此两次打印可以不带换行,但第二次打印要考虑第一次的长度),则需要更具状态的打印机(以记住已使用的行上字符)或发明一些稍微复杂的具有完整功能的东西。我将把这留作练习。

2

难点在于获取控制台(Windows世界)或终端(Unix)的大小,因为我不知道任何可移植的方法来获取它。这涉及到以下操作(如@MaximeB提出的Gist所示):

  • 对于Windows(通过ctypes.windll),使用Windows API中的GetConsoleScreenBufferInfo
  • 在Linux或其他Unix上使用fcntl.ioctl

不谈可能存在的特殊情况……但如果你只使用Windows,那么Gist就足够满足你的需求。

一旦找到了宽度,或者您可以接受静态宽度为72或80或其他任何值,则可以使用texwrap模块完成此操作:

for i in textwrap.wrap(text, 72):
    print i

提供:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vitae
odio quis felis consectetur blandit. Etiam mattis vehicula ex id
sodales. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris
fermentum semper nisi vel aliquam. Ut nec facilisis lectus. Maecenas
auctor blandit condimentum. Donec finibus orci ac imperdiet congue.
Pellentesque sem leo, commodo non metus ac, posuere maximus lorem. Class
aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos.

1

你可以查看这个Gist

然后使用返回的值来相应地拆分字符串,以便在后续的print调用中使用。

IDLE shell:

宽度可以通过sys.stdout.shell.width进行检索,在任何其他环境中都会引发AttributeError(在这种情况下,您将使用gist)。


另外需要补充的是:可以使用 sys.stdout.shell.width 获取 IDLE shell 的宽度,但在其他环境中会引发 AttributeError 错误(此时应使用 gist)。 - Tadhg McDonald-Jensen
不确定这个编辑是否有添加任何内容,因为我的评论直接在下面,但格式更好了... - Tadhg McDonald-Jensen
抱歉,我在添加标题时作为编辑建议了:/ - Maxime B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接