Sıralı sözlükleri düzgün bir şekilde yazdırmanın bir yolu var mı?


97

Python'daki pprint modülünü beğendim. Bunu test etmek ve hata ayıklamak için çok kullanıyorum. Çıktının terminal pencereme tam olarak oturduğundan emin olmak için sık sık genişlik seçeneğini kullanıyorum.

Python 2.7'de yeni sıralı sözlük türünü (gerçekten sevdiğim başka bir harika özellik) ekleyene kadar iyi çalıştı . Sıralı bir sözlüğü güzelce yazdırmaya çalışırsam, güzel görünmüyor. Her anahtar / değer çiftinin kendi satırında olması yerine, her şey birçok kez kaydırılan ve okunması zor olan uzun bir satırda görünür.

Burada, eski sırasız sözlükler gibi, onu güzelce basmanın bir yolu olan var mı? Yeterince zaman harcarsam, muhtemelen PrettyPrinter.format yöntemini kullanarak bir şeyler çözebilirim, ancak burada herhangi birinin zaten bir çözüm bilip bilmediğini merak ediyorum.

GÜNCELLEME: Bunun için bir hata raporu hazırladım. Bunu http://bugs.python.org/issue10592 adresinde görebilirsiniz .


Yanıtlar:


134

Geçici bir çözüm olarak, JSON formatında döküm almayı deneyebilirsiniz. Bazı tür bilgilerini kaybedersiniz, ancak güzel görünür ve düzeni korur.

import json

pprint(data, indent=4)
# ^ugly

print(json.dumps(data, indent=4))
# ^nice

7
@scottmrogowski Neden basitçe değil pprint.pprint(dict(data))?
Alfe

2
pprint.pprint(dict(data))Anahtarların sırasını önemsemiyorsanız iyi çalışır. Şahsen ben dilek __repr__için OrderedDictböyle çıktı üretmekle kalmaz tuşların düzeni korumak olacaktır.
ws_e_c421

9
@Alfe Eğer dikte OrderedDicts'i iç içe geçirdiyse, güzel bir şekilde gösterilmeyecekler
Catskul

1
Ayrıca tamsayılarda anahtar olarak başarısız
DimmuR

2
@Alfe: Çünkü o zaman çıktı sipariş edilmedi. İlk etapta dikte yerine OrderedDict kullanılmasının nedeni, sıranın önemli olmasıdır.
Teekin

15

Aşağıdakiler, OrderedDict'inizin sırası bir alfa sıralaması ise çalışacaktır, çünkü pprint baskıdan önce bir dikteyi sıralayacaktır.

pprint(dict(o.items()))

2
OrderedDicts ekleme siparişine göre sıralandığından, bu muhtemelen kullanımların küçük bir yüzdesi için geçerlidir. Ne olursa olsun, OD'yi a'ya dönüştürmek, dicther şeyin tek bir satıra yerleştirilmesi sorununu ortadan kaldırmalıdır.
martineau

9

İşte hisse senedi pprint()işlevini dahili olarak geçersiz kılarak ve kullanarak çalışan başka bir cevap . Aksine benim tek önceki o olacak ele OrderedDict'böyle bir şekilde başka bir kaba içerde listve ayrıca verilen isteğe bağlı herhangi bir anahtar kelime argümanları ele almak gerekir - ancak diğeri tanınan bu çıkışı üzerinde kontrol aynı derecede sahip değildir.

Stok fonksiyonunun çıktısını geçici bir tampona yeniden yönlendirerek çalışır ve ardından bunu çıktı akışına göndermeden önce sözcük sarar. Üretilen nihai çıktı olağanüstü derecede güzel olmasa da, nezih ve geçici çözüm olarak kullanmak için "yeterince iyi" olabilir.

2.0 Güncellemesi

Standart kitaplık textwrapmodülü kullanılarak basitleştirildi ve hem Python 2 hem de 3'te çalışacak şekilde değiştirildi.

from collections import OrderedDict
try:
    from cStringIO import StringIO
except ImportError:  # Python 3
    from io import StringIO
from pprint import pprint as pp_pprint
import sys
import textwrap

def pprint(object, **kwrds):
    try:
        width = kwrds['width']
    except KeyError: # unlimited, use stock function
        pp_pprint(object, **kwrds)
        return
    buffer = StringIO()
    stream = kwrds.get('stream', sys.stdout)
    kwrds.update({'stream': buffer})
    pp_pprint(object, **kwrds)
    words = buffer.getvalue().split()
    buffer.close()

    # word wrap output onto multiple lines <= width characters
    try:
        print >> stream, textwrap.fill(' '.join(words), width=width)
    except TypeError:  # Python 3
        print(textwrap.fill(' '.join(words), width=width), file=stream)

d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
lod = [OrderedDict((('john',1), ('paul',2), ('mary',3))),
       OrderedDict((('moe',1), ('curly',2), ('larry',3))),
       OrderedDict((('weapons',1), ('mass',2), ('destruction',3)))]

Örnek çıktı:

pprint(d, width=40)

»   {'john': 1, 'mary': 3, 'paul': 2}

pprint(od, width=40)

» OrderedDict([('john', 1), ('paul', 2),
   ('mary', 3)])

pprint(lod, width=40)

» [OrderedDict([('john', 1), ('paul', 2),
   ('mary', 3)]), OrderedDict([('moe', 1),
   ('curly', 2), ('larry', 3)]),
   OrderedDict([('weapons', 1), ('mass',
   2), ('destruction', 3)])]


Bunu denedim ve işe yarıyor. Dediğin gibi en güzel değil ama şimdiye kadar gördüğüm en iyi çözüm.
Elias Zamaria

7

Sıralı bir dikteyi yazdırmak için, örneğin

from collections import OrderedDict

d=OrderedDict([
    ('a', OrderedDict([
        ('a1',1),
        ('a2','sss')
    ])),
    ('b', OrderedDict([
        ('b1', OrderedDict([
            ('bb1',1),
            ('bb2',4.5)])),
        ('b2',4.5)
    ])),
])

Yaparım

def dict_or_OrdDict_to_formatted_str(OD, mode='dict', s="", indent=' '*4, level=0):
    def is_number(s):
        try:
            float(s)
            return True
        except ValueError:
            return False
    def fstr(s):
        return s if is_number(s) else '"%s"'%s
    if mode != 'dict':
        kv_tpl = '("%s", %s)'
        ST = 'OrderedDict([\n'; END = '])'
    else:
        kv_tpl = '"%s": %s'
        ST = '{\n'; END = '}'
    for i,k in enumerate(OD.keys()):
        if type(OD[k]) in [dict, OrderedDict]:
            level += 1
            s += (level-1)*indent+kv_tpl%(k,ST+dict_or_OrdDict_to_formatted_str(OD[k], mode=mode, indent=indent, level=level)+(level-1)*indent+END)
            level -= 1
        else:
            s += level*indent+kv_tpl%(k,fstr(OD[k]))
        if i!=len(OD)-1:
            s += ","
        s += "\n"
    return s

print dict_or_OrdDict_to_formatted_str(d)

Hangi verim

"a": {
    "a1": 1,
    "a2": "sss"
},
"b": {
    "b1": {
        "bb1": 1,
        "bb2": 4.5
    },
    "b2": 4.5
}

veya

print dict_or_OrdDict_to_formatted_str(d, mode='OD')

hangi sonuç verir

("a", OrderedDict([
    ("a1", 1),
    ("a2", "sss")
])),
("b", OrderedDict([
    ("b1", OrderedDict([
        ("bb1", 1),
        ("bb2", 4.5)
    ])),
    ("b2", 4.5)
]))

5

İşte uygulamasını hackleyen bir yol pprint. pprinttuşları yazdırmadan önce sıralar, bu yüzden sırayı korumak için anahtarları istediğimiz şekilde sıralamamız yeterlidir.

Bunun items()işlevi etkilediğini unutmayın . Bu nedenle, pprint'i yaptıktan sonra geçersiz kılınan işlevleri korumak ve geri yüklemek isteyebilirsiniz.

from collections import OrderedDict
import pprint

class ItemKey(object):
  def __init__(self, name, position):
    self.name = name
    self.position = position
  def __cmp__(self, b):
    assert isinstance(b, ItemKey)
    return cmp(self.position, b.position)
  def __repr__(self):
    return repr(self.name)

OrderedDict.items = lambda self: [
    (ItemKey(name, i), value)
    for i, (name, value) in enumerate(self.iteritems())]
OrderedDict.__repr__ = dict.__repr__

a = OrderedDict()
a[4] = '4'
a[1] = '1'
a[2] = '2'
print pprint.pformat(a) # {4: '4', 1: '1', 2: '2'}

2
Güzel, ancak alt türlere ayırmak ve ardından işlevleri geçersiz kılmak daha iyidir.
xmedeko

3

İşte bir OrderedDict'i güzelce basma yaklaşımım

from collections import OrderedDict
import json
d = OrderedDict()
d['duck'] = 'alive'
d['parrot'] = 'dead'
d['penguin'] = 'exploded'
d['Falcon'] = 'discharged'
print(d)
print(json.dumps(d,indent=4))

OutPut:

OrderedDict([('duck', 'alive'), ('parrot', 'dead'), ('penguin', 'exploded'), ('Falcon', 'discharged')])

{
    "duck": "alive",
    "parrot": "dead",
    "penguin": "exploded",
    "Falcon": "discharged"
}

Sıralı sırayla anahtarlarla güzel bir sözlük yazdırmak istiyorsanız

print(json.dumps(indent=4,sort_keys=True))
{
    "Falcon": "discharged",
    "duck": "alive",
    "parrot": "dead",
    "penguin": "exploded"
}

@AlxVallejo kullanıyor olabilirsiniz python3. Lütfen kontrol edin
CHINTAN VADGAMA

2

Bu oldukça kaba, ancak sadece herhangi bir keyfi Haritalama ve Yinelemeden oluşan bir veri yapısını görselleştirmek için bir yola ihtiyacım vardı ve pes etmeden önce bulduğum şey buydu. Özyinelemeli, bu yüzden iç içe geçmiş yapılara ve listelerden geçecek. Hemen hemen her şeyi işlemek için koleksiyonlardan Mapping ve Yinelenebilir soyut temel sınıfları kullandım.

Kısa python koduyla neredeyse yaml benzeri bir çıktı almayı hedefliyordum, ancak tam olarak başaramadım.

def format_structure(d, level=0):
    x = ""
    if isinstance(d, Mapping):
        lenk = max(map(lambda x: len(str(x)), d.keys()))
        for k, v in d.items():
            key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k)
            x += key_text + ": " + format_structure(v, level=level+lenk)
    elif isinstance(d, Iterable) and not isinstance(d, basestring):
        for e in d:
            x += "\n" + " "*level + "- " + format_structure(e, level=level+4)
    else:
        x = str(d)
    return x

ve OrderedDict ve OrderedDicts listelerini kullanarak bazı test verileri ... (sheesh Python'un OrderedDict değişmez değerlerine ihtiyacı var çok kötü ...)

d = OrderedDict([("main",
                  OrderedDict([("window",
                                OrderedDict([("size", [500, 500]),
                                             ("position", [100, 900])])),
                               ("splash_enabled", True),
                               ("theme", "Dark")])),
                 ("updates",
                  OrderedDict([("automatic", True),
                               ("servers",
                                [OrderedDict([("url", "http://server1.com"),
                                              ("name", "Stable")]),
                                 OrderedDict([("url", "http://server2.com"),
                                              ("name", "Beta")]),
                                 OrderedDict([("url", "http://server3.com"),
                                              ("name", "Dev")])]),
                               ("prompt_restart", True)])),
                 ("logging",
                  OrderedDict([("enabled", True),
                               ("rotate", True)]))])

print format_structure(d)

aşağıdaki çıktıyı verir:

   main: 
               window: 
                         size: 
                             - 500
                             - 500
                     position: 
                             - 100
                             - 900
       splash_enabled: True
                theme: Dark
updates: 
            automatic: True
              servers: 
                     - 
                          url: http://server1.com
                         name: Stable
                     - 
                          url: http://server2.com
                         name: Beta
                     - 
                          url: http://server3.com
                         name: Dev
       prompt_restart: True
logging: 
       enabled: True
        rotate: True

Daha iyi hizalama için str.format () kullanma yolunda bazı düşüncelerim vardı, ancak derinlemesine incelemek istemedim. Alan genişliklerini, istediğiniz hizalama türüne bağlı olarak dinamik olarak belirtmeniz gerekir, bu da karmaşık veya külfetli olabilir.

Her neyse, bu bana verilerimi okunabilir hiyerarşik bir şekilde gösteriyor, yani bu benim için çalışıyor!


2
def pprint_od(od):
    print "{"
    for key in od:
        print "%s:%s,\n" % (key, od[key]) # Fixed syntax
    print "}"

İşte gidiyor ^^

for item in li:
    pprint_od(item)

veya

(pprint_od(item) for item in li)

OrderedDicts'i ve diğer türleri güzelce yazdırabilen bir işleve sahip olmanın bir yolunu arıyorum. İşlevinizi, OrderedDicts listesini güzelce yazdırmak için nasıl kullanacağımı anlamıyorum.
Elias Zamaria

-1 pprint_od()işlev değil iş gelmez - for key, item in odBir de deyim sonuçları ValueError: too many values to unpack ve girintili tek çıkış kesindir " }" vekey, item de printparantez içinde olmak deyimi gerek. İşte gidiyor ^^
martineau

2

Bu kutsal olmayan maymun yaması tabanlı hack'i python3.5 üzerinde test ettim ve işe yarıyor:

pprint.PrettyPrinter._dispatch[pprint._collections.OrderedDict.__repr__] = pprint.PrettyPrinter._pprint_dict


def unsorted_pprint(data):
    def fake_sort(*args, **kwargs):
        return args[0]
    orig_sorted = __builtins__.sorted
    try:
        __builtins__.sorted = fake_sort
        pprint.pprint(data)
    finally:
        __builtins__.sorted = orig_sorted

Her pprintzamanki dikteye dayalı özeti kullanırsınız ve ayrıca yazdırma için gerçekte hiçbir tuşun sıralanmaması için arama süresince sıralamayı devre dışı bırakırsınız.


ayrıca pretty_print.pyyerel bir modül olarak kopyalayabilir ve onu hackleyebilirsiniz ( sortedaramayı veya ne isterseniz onu kaldırabilirsiniz ).
Karl Rosaen

2

Python 3.8'den itibaren: anahtar kelime parametresini pprint.PrettyPrinterortaya çıkarır sort_dicts.

Gerçek varsayılan olarak ayarlayarak sahte Sözlük sıralanmamış bırakacaktır.

>>> from pprint import PrettyPrinter

>>> x = {'John': 1,
>>>      'Mary': 2,
>>>      'Paul': 3,
>>>      'Lisa': 4,
>>>      }

>>> PrettyPrinter(sort_dicts=False).pprint(x)

Çıktı:

{'John': 1, 
 'Mary': 2, 
 'Paul': 3,
 'Lisa': 4}

Referans: https://docs.python.org/3/library/pprint.html


1

pprint()Yöntem sadece başlatıyordur __repr__()bunun şeylerin yöntemini ve OrderedDict's yönteminde çok fazla bir şey görünmüyor (veya bir veya bir şey yoktur).

YAZDIRMA ÇIKTISINDA GÖRÜNÜR OLAN SİPARİŞ KONUSUNDA DİKKAT ETMİYORSANIZ , işe yarayacak ucuz bir çözüm aşağıda verilmiştir ; bu, aşağıdaki durumlarda büyük olabilir:

class PrintableOrderedDict(OrderedDict):
    def __repr__(self):
        return dict.__repr__(self)

Aslında düzenin korunmamasına şaşırdım ... ah iyi.


Bir python sözlüğü bir hashmap kullanılarak uygulanır. Bu nedenle, bir OrderedDict'i (temel bir dikt ve sırayı korumak için bir listenin birleşimi) bir dikte dönüştürdüğünüzde, tüm sipariş bilgilerini kaybedersiniz. Ayrıca repr yönteminin, nesneyi python kodunda temsil edecek bir dize döndürmesi beklenir. Diğer bir deyişle, obj == eval (repr (obj)) veya en azından repr (obj) == repr (eval (repr (obj))). OrderedDict'in repr'ı bunu gayet iyi yapıyor. dict .__ repr__ size çok okunabilir bir sunum vermek, tamamen dikte edebi ifadenin ('{' ve '}', vb.) bir yan etkisidir. OrderedDict buna sahip değil.
Mart75

1

Ayrıca kzh cevabının bu basitleştirmesini de kullanabilirsiniz :

pprint(data.items(), indent=4)

Sırayı korur ve hemen hemen webwurst cevabıyla aynı çıktı verir ( json dökümü aracılığıyla yazdır ).


1

Python <3.8 (ör. 3.6) için:

Maymun yama pprint's sortedsıralama önlemek amacıyla. Bu, yinelemeli olarak çalışan her şeyin avantajına da sahip olacak ve jsonörneğin widthparametresi kullanması gereken kişi için seçenekten daha uygundur :

import pprint
pprint.sorted = lambda arg, *a, **kw: arg

>>> pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)
{'z': 1,
 'a': 2,
 'c': {'z': 0,
       'a': 1}}

Düzenleme: temizleme

Bu kirli işten sonra temizlemek için şunu yapın: pprint.sorted = sorted

Gerçekten temiz bir çözüm için bir bağlam yöneticisi bile kullanabilirsiniz:

import pprint
import contextlib

@contextlib.contextmanager
def pprint_ordered():
    pprint.sorted = lambda arg, *args, **kwargs: arg
    yield
    pprint.sorted = sorted

# usage:

with pprint_ordered():
    pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)

# without it    
pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)

# prints: 
#    
# {'z': 1,
#  'a': 2,
#  'c': {'z': 0,
#        'a': 1}}
#
# {'a': 2,
#  'c': {'a': 1,
#        'z': 0},
#  'z': 1}

0

' pprint()Ları için çağrıları yeniden tanımlayabilir ve durdurabilirsiniz OrderedDict. İşte basit bir örnek. Yazılı olarak, OrderedDictiptal kodu herhangi isteğe yok sayar stream, indent, widthveya depthgeçmiş olabilir anahtar kelimeleri, fakat onları uygulamak için geliştirilmiş olabilir. Ne yazık ki, bu teknik, bir şekilde, başka bir konteynır içerisine bunları işlemez listarasında OrderDict's

from collections import OrderedDict
from pprint import pprint as pp_pprint

def pprint(obj, *args, **kwrds):
    if not isinstance(obj, OrderedDict):
        # use stock function
        return pp_pprint(obj, *args, **kwrds)
    else:
        # very simple sample custom implementation...
        print "{"
        for key in obj:
            print "    %r:%r" % (key, obj[key])
        print "}"

l = [10, 2, 4]
d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
pprint(l, width=4)
# [10,
#  2,
#  4]
pprint(d)
# {'john': 1, 'mary': 3, 'paul': 2}

pprint(od)
# {
#     'john':1
#     'paul':2
#     'mary':3
# }

0

Sözlük öğelerinin tümü tek türdeyse, harika veri işleme kitaplığını kullanabilirsiniz pandas:

>>> import pandas as pd
>>> x = {'foo':1, 'bar':2}
>>> pd.Series(x)
bar    2
foo    1
dtype: int64

veya

>>> import pandas as pd
>>> x = {'foo':'bar', 'baz':'bam'}
>>> pd.Series(x)
baz    bam
foo    bar
dtype: object

2
Bu kod ne yapacak? Buradaki diğer çözümlere göre ne gibi avantajları var?
Elias Zamaria
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.