如何在Python中打印“漂亮”的字符串输出

33

我有一个字典列表,包含classid、dept、coursenum、area和title字段,它们是从一个SQL查询中获取的。我想以人类可读的格式输出这些值。我考虑在每个列的顶部添加一个列标题,然后在每个列中输出相应的内容,例如:

CLASSID     DEPT     COURSE NUMBER        AREA     TITLE
foo         bar      foo                  bar      foo
yoo         hat      yoo                  bar      hat

(自然是具有标准对齐/间距)

我该如何在Python中完成这个任务?


你可以尝试使用Padnums模块。示例输出似乎符合您的要求。或者使用这种表格缩进方法。我没有使用过任何一个,但它们是在谷歌搜索“python pretty print table”(http://www.google.com/search?q=python+pretty+print+table)的前几个结果中。 - unholysampler
如需打印一个对齐的表格 没有表头,请参阅此处:如何将字典列表打印为对齐的表格? - Georgy
5个回答

69

Python标准字符串格式化可能已经足够。

# assume that your data rows are tuples
template = "{0:8}|{1:10}|{2:15}|{3:7}|{4:10}" # column widths: 8, 10, 15, 7, 10
print template.format("CLASSID", "DEPT", "COURSE NUMBER", "AREA", "TITLE") # header
for rec in your_data_source: 
  print template.format(*rec)

或者

# assume that your data rows are dicts
template = "{CLASSID:8}|{DEPT:10}|{C_NUM:15}|{AREA:7}|{TITLE:10}" # same, but named
print template.format( # header
  CLASSID="CLASSID", DEPT="DEPT", C_NUM="COURSE NUMBER", 
  AREA="AREA", TITLE="TITLE"
) 
for rec in your_data_source: 
  print template.format(**rec)

通过调整对齐方式、内边距和格式规范来获得最佳结果。


11
class TablePrinter(object):
    "Print a list of dicts as a table"
    def __init__(self, fmt, sep=' ', ul=None):
        """        
        @param fmt: list of tuple(heading, key, width)
                        heading: str, column label
                        key: dictionary key to value to print
                        width: int, column width in chars
        @param sep: string, separation between columns
        @param ul: string, character to underline column label, or None for no underlining
        """
        super(TablePrinter,self).__init__()
        self.fmt   = str(sep).join('{lb}{0}:{1}{rb}'.format(key, width, lb='{', rb='}') for heading,key,width in fmt)
        self.head  = {key:heading for heading,key,width in fmt}
        self.ul    = {key:str(ul)*width for heading,key,width in fmt} if ul else None
        self.width = {key:width for heading,key,width in fmt}

    def row(self, data):
        return self.fmt.format(**{ k:str(data.get(k,''))[:w] for k,w in self.width.iteritems() })

    def __call__(self, dataList):
        _r = self.row
        res = [_r(data) for data in dataList]
        res.insert(0, _r(self.head))
        if self.ul:
            res.insert(1, _r(self.ul))
        return '\n'.join(res)

并且正在使用中:

data = [
    {'classid':'foo', 'dept':'bar', 'coursenum':'foo', 'area':'bar', 'title':'foo'},
    {'classid':'yoo', 'dept':'hat', 'coursenum':'yoo', 'area':'bar', 'title':'hat'},
    {'classid':'yoo'*9, 'dept':'hat'*9, 'coursenum':'yoo'*9, 'area':'bar'*9, 'title':'hathat'*9}
]

fmt = [
    ('ClassID',       'classid',   11),
    ('Dept',          'dept',       8),
    ('Course Number', 'coursenum', 20),
    ('Area',          'area',       8),
    ('Title',         'title',     30)
]

print( TablePrinter(fmt, ul='=')(data) )

产生

ClassID     Dept     Course Number        Area     Title                         
=========== ======== ==================== ======== ==============================
foo         bar      foo                  bar      foo                           
yoo         hat      yoo                  bar      hat                           
yooyooyooyo hathatha yooyooyooyooyooyooyo barbarba hathathathathathathathathathat

9
如果您想保持简单,可以将字符串左对齐到特定数量的字符:
print string1.ljust(20) + string2.ljust(20)

4

这个函数将列表推导式发挥到了极致,但它以最佳性能实现了您要寻找的功能:

算法:

  1. 在每列中找到最长的字段;例如,'max(map(len, column_vector))'
  2. 对于每个字段(从左到右,从上到下),调用 str.ljust 将其对齐到所属列的左边界。
  3. 使用所需数量的分隔空格(创建一行)连接字段。
  4. 使用换行符连接行集合。

row_collection:可迭代对象(字典/集合/列表)的列表,每个对象包含一行数据。

key_list:指定要从每行读取的键/索引以形成列的列表。

def getPrintTable(row_collection, key_list, field_sep=' '*4):
  return '\n'.join([field_sep.join([str(row[col]).ljust(width)
    for (col, width) in zip(key_list, [max(map(len, column_vector))
      for column_vector in [ [v[k]
        for v in row_collection if k in v]
          for k in key_list ]])])
            for row in row_collection])

1

对我来说,最简单的方法是将其转换为数组的数组:

datas = [
  [ 'ClassID', 'Dept', 'Course Number', 'Area', 'Title' ],
  [ 'foo', 'bar', 'foo', 'bar', 'foo' ],
  [ 'yoo', 'hat', 'yoo', 'bar', 'hat' ],
  [ 'line', 'last', 'fun', 'Lisa', 'Simpson' ]
]

for j, data in enumerate(datas):
  if j == 0:
    # print(list(data))
    max = 0
    for i in datas:
      max_len =  len(''.join(i))
      if max_len > max:
        max = max_len
        max = max + 4 * len(datas[0])
    max = 79
    print(f"max is {max}")
    print('+' + '-' * max + '+')
    v1, v2, v3, v4, v5 = datas[0]
    print(f"|{v1:^15s}|{v2:^15s}|{v3:^15s}|{v4:^15s}|{v5:^15s}|")
    print('+' +  '-' * max + '+')
    continue
  else:
    # print( '+' + '-' * max + '+')
    v1, v2, v3, v4, v5 = data
    print(f"|{v1:^15s}|{v2:^15s}|{v3:^15s}|{v4:^15s}|{v5:^15s}|")
    print('+' +  '-' * max + '+')
    # print(type(data))

你得到了这个:

你得到了这个:

+-------------------------------------------------------------------------------+
|    ClassID    |     Dept      | Course Number |     Area      |     Title     |
+-------------------------------------------------------------------------------+
|      foo      |      bar      |      foo      |      bar      |      foo      |
+-------------------------------------------------------------------------------+
|      yoo      |      hat      |      yoo      |      bar      |      hat      |
+-------------------------------------------------------------------------------+
|     line      |     last      |      fun      |     Lisa      |    Simpson    |
+-------------------------------------------------------------------------------+

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