Могу ли я избежать вывода отсортированного словаря после использования pprint.pprint в python?

Код такой:

from pprint import pprint
d = {"b" : "Maria", "c" : "Helen", "a" : "George"}
pprint(d, width = 1)

Результат:

{'a': 'George',
'b': 'Maria',
'c': 'Helen'}

Но желаемый результат:

{'b': 'Maria',
'c': 'Helen',
'a': 'George'}

Можно ли это сделать с помощью pprint или есть другой способ?

OrderedDict или используйте функцию для сортировки ключей и печати их по отдельности. Но еще одно замечание: какое вам дело до того, есть ли в словаре порядок?
Francisco 10.08.2018 16:12
docs.python.org/3/library/pprint.html говорит: «Словари сортируются по ключу перед вычислением отображения». Не похоже, что это необязательно.
Kevin 10.08.2018 16:13

@EdChum, @Francisco, конечно, OrderedDict отобразит результаты в упорядоченном порядке. Но если передать один в pprint, он не будет «красивым»: он будет выглядеть как OrderedDict([items go here]). Не очень похоже на желаемый результат.

Kevin 10.08.2018 16:15

@Kevin Я только что заметил этот бит, вы правы, это неизбежно с pprint, поэтому OP должен рассмотреть другой метод

EdChum 10.08.2018 16:16

Вы могли бы создать подкласс PrettyPrinter и переопределить pformat, чтобы получить желаемый результат. Хотя я не уверен

Patrick Haugh 10.08.2018 16:18

@Kevin, Конечно, но если я использую простой принт, то беру несортированный результат, как хочу. Проблема в том, что мне нужно распечатать dict точно так, как показано выше, но простая печать печатает все в одной строке, поэтому я не могу его использовать.

Maria Pantsiou 10.08.2018 16:21
10
6
1 751
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вы должны использовать OrderedDict из библиотеки коллекций python, чтобы сохранить постоянный порядок

from collections import OrderedDict
from pprint import pprint
d = OrderedDict({"b" : "Maria", "c" : "Helen", "a" : "George"})
pprint(d, width = 1)

Обновлено:

Поскольку вывод важен, вы можете использовать следующий код, это взлом, но вы создаете функцию для реализации этой функции:

from collections import OrderedDict
d = OrderedDict({"b" : "Maria", "c" : "Helen", "a" : "George"})
print('{', end='')
total_len = len(d)
current_index = 1
for key, value in d.items():
    print('\''+key+'\': \'' + value+ '\'', end='')
    if current_index<total_len:
        print(',')
    else:
        print('}')
    current_index += 1

OP хочет изменить поведение pprint, это не касается поддержания порядка вставки

EdChum 10.08.2018 16:20

pprint будет печатать результат в соответствии с сохраненным значением. dict по умолчанию не поддерживает порядок или вставку, поэтому вывод печатается в этом порядке. Следовательно, я чувствую, что использование заказанного дикта послужит цели

argo 10.08.2018 16:24

Вывод этого кода не очень похож на желаемый.

Kevin 10.08.2018 16:26

Это решает проблему сортировки, но результат сильно отличается от желаемого.

Maria Pantsiou 10.08.2018 16:34

Я обновил ответ, чтобы распечатать его в соответствии с требованиями. Я надеюсь это решит твою проблему

argo 10.08.2018 16:39

@ Arghya Saha, Отлично, это решает мою проблему! Спасибо!

Maria Pantsiou 10.08.2018 16:45

Если вы прочитаете исходный код pprint.py, вы обнаружите, что в PrettyPrinter._pprint_dict() метод, отвечающий за форматирование dicts:

def _pprint_dict(self, object, stream, indent, allowance, context, level):
    write = stream.write
    write('{')
    if self._indent_per_level > 1:
        write((self._indent_per_level - 1) * ' ')
    length = len(object)
    if length:
        items = sorted(object.items(), key=_safe_tuple)
        self._format_dict_items(items, stream, indent, allowance + 1,
                                context, level)
    write('}')

_dispatch[dict.__repr__] = _pprint_dict

Есть эта строка items = sorted(object.items(), key=_safe_tuple), поэтому элементы dict всегда сначала сортируются перед обработкой для форматирования, и вам придется переопределить ее самостоятельно, скопировав и вставив ее и удалив неправильную строку в своем собственном скрипте:

import pprint as pp
def _pprint_dict(self, object, stream, indent, allowance, context, level):
    write = stream.write
    write('{')
    if self._indent_per_level > 1:
        write((self._indent_per_level - 1) * ' ')
    length = len(object)
    if length:
        self._format_dict_items(object.items(), stream, indent, allowance + 1,
                                context, level)
    write('}')
pp.PrettyPrinter._dispatch[dict.__repr__] = _pprint_dict

и что:

pp.pprint({"b" : "Maria", "c" : "Helen", "a" : "George"}, width=1)

выведет (в Python 3.6+):

{'b': 'Maria',
 'c': 'Helen',
 'a': 'George'}

Проблема, с которой я столкнулся при создании подклассов, заключается в том, что частные методы вызываются только тогда, когда стандартное представление превышает ширину. Хотя вы преодолели эту проблему, установив width = 1, общее решение потребует также переопределения метода PrettyPrinter.format.

Olivier Melançon 10.08.2018 19:56

Верно. Я добавил новый ответ с более общим подходом.

blhsing 13.04.2019 02:59
Ответ принят как подходящий

Python 3.8 или новее:

Вы можете использовать sort_dicts=False, чтобы он не сортировал их по алфавиту:

pprint.pprint(data, sort_dicts=False)

Python 3.7 или старше:

Начиная с Python 3.7 (или 3.6 в случае cPython), dict сохраняет порядок вставки. Для любой предыдущей версии вам нужно будет использовать OrderedDict, чтобы ключи были в порядке.

Хотя, из документ на pprint:

Dictionaries are sorted by key before the display is computed.

Это означает, что pprint в любом случае нарушит ваш желаемый порядок.

Альтернативный метод:

Вы также можете использовать json.dumps для красивой печати ваших данных.

Код:

import json
from collections import OrderedDict

# For Python 3.6 and prior, use an OrderedDict
d = OrderedDict(b="Maria", c="Helen", a="George")

print(json.dumps(d, indent=1))

Выход:

{
 "b": "Maria",
 "c": "Helen",
 "a": "George"
}

Python 3.7 для этого не работал, но последний код - это именно то, что я искал, большое вам спасибо.

Maria Pantsiou 10.08.2018 19:30

@MariaPantsiou Вы правы, pprint сортирует ваши ключи, я обновлю ответ.

Olivier Melançon 10.08.2018 19:41

Более общее решение - использовать unittest.mock.patch для переопределения встроенной функции sorted с функцией, которая ничего не делает, кроме как возвращает данный первый аргумент:

import pprint
from unittest.mock import patch

def unsorted_pprint(*args, **kwargs):
    with patch('builtins.sorted', new=lambda l, **_: l):
        orig_pprint(*args, **kwargs)

orig_pprint = pprint.pprint
pprint.pprint = unsorted_pprint

и что:

pprint.pprint({"b" : "Maria", "c" : "Helen", "a" : "George"})

выходы:

{'b': 'Maria', 'c': 'Helen', 'a': 'George'}

Начиная с Python 3.8, pprint имеет аргумент ключевого слова sort_dicts, который вы можете установить, чтобы предотвратить сортировку ключей словаря по алфавиту. Если вы установите для него значение false, он будет использовать порядок словарей по умолчанию (например, порядок вставки).

Пример:

>>> from pprint import pprint
>>> pprint(dict(z=0, a=1), sort_dicts=False)
{'z': 0, 'a': 1}

Спасибо, первый ответ, который действительно работает и прост

Peter Franek 31.08.2020 12:50

Другие вопросы по теме