web-dev-qa-db-fra.com

Comment imprimer une sortie de chaîne "jolie" dans Python

J'ai une liste de dict avec les champs classid, dept, coursenum, area et title d'une requête sql. Je voudrais sortir les valeurs dans un format lisible par l'homme. Je pensais à un en-tête de colonne en haut de chaque, puis dans chaque colonne, la sortie appropriée, à savoir:

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

(évidemment avec alignement/espacement standard)

Comment pourrais-je accomplir cela en python?

27
themaestro

Standard Python formatage de chaîne peut suffire.

# 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)

Ou

# 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)

Jouez avec les spécificateurs d'alignement, de remplissage et de format exact pour obtenir les meilleurs résultats.

58
9000
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)

et en cours d'utilisation:

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) )

produit

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

Vous pouvez simplement justifier la chaîne à un certain nombre de caractères si vous voulez rester simple:

print string1.ljust(20) + string2.ljust(20)
5
Evan Jensen

Cette fonction amène la compréhension des listes à un niveau extrême, mais elle accomplit ce que vous recherchez avec des performances optimales:

algorithme:

  1. trouver le champ le plus long dans chaque colonne; c'est-à-dire, 'max (map (len, column_vector))'
  2. pour chaque champ (de gauche à droite, de haut en bas), appelez str.ljust pour l'aligner sur la limite gauche de la colonne à laquelle il appartient.
  3. joindre des champs avec la quantité souhaitée d'espaces de séparation (création d'une ligne).
  4. rejoindre la collection de lignes avec une nouvelle ligne.

row_collection: liste des itérables (dict/sets/lists), chacune contenant des données pour une ligne.

key_list: liste qui spécifie quelles clés/index lire à partir de chaque ligne pour former des colonnes.

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])
4
Daniel Sparks