Пожалуйста, прекратите использовать pprint для печати словарей.

Python

Впервые опубликовано в публичном аккаунте WeChat: Время программирования на Python

Адрес интернет-блога:Python.is для BM.com/en/latest/ от…


1. Проблема Тукао

Вы должны быть знакомы с pprint в Python, верно?

Каждый раз, когда вы ищете в любой поисковой системе, как печатать красивые словари или форматировать строки, большинство людей порекомендуют вам использовать это.

Например, следующая строка json или словарь (я нашла в интернете), если она не отформатирована и не украшена, то вообще не читается.

[{"id":1580615,"name":"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":"2011-2017 你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":"斗鱼271934 走过路过不要错过,这里有最好的鸡儿"}]

Если вы не хотите видеть кучу многословных слов, используйте pprint, который все настоятельно рекомендуют, чтобы увидеть, каков эффект (следующее продемонстрировано в Python 2, эффект отличается в Python 3).

>>> info=[{"id":1580615,"name":"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":"2011-2017 你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":"斗鱼271934 走过路过不要错过,这里有最好的鸡儿"}]
>>> 
>>> from pprint import pprint
>>> pprint(info)
[{'des': '2011-2017 \xe4\xbd\xa0\xe7\x9a\x84\xe9\x93\x81\xe5\xa4\xb4\xe5\xa8\x83\xe4\xb8\x80\xe7\x9b\xb4\xe5\x9c\xa8\xe8\xbf\x99\xe5\x84\xbf\xe3\x80\x82\xe4\xb8\xad\xe5\x9b\xbd\xe6\x9c\x80\xe5\xa4\xa7\xe7\x9a\x84\xe5\xae\x9e\xe5\x90\x8d\xe5\x88\xb6SNS\xe7\xbd\x91\xe7\xbb\x9c\xe5\xb9\xb3\xe5\x8f\xb0\xef\xbc\x8c\xe5\xab\xa9\xe5\xa4\xb4\xe9\x9d\x92',
  'downloadUrl': 'app/com.renren.mobile.android/com.renren.mobile.android.apk',
  'iconUrl': 'app/com.renren.mobile.android/icon.jpg',
  'id': 1580615,
  'name': '\xe7\x9a\xae\xe7\x9a\x84\xe5\x98\x9b',
  'packageName': 'com.renren.mobile.android',
  'size': 21803987,
  'stars': 2},
 {'des': '\xe6\x96\x97\xe9\xb1\xbc271934 \xe8\xb5\xb0\xe8\xbf\x87\xe8\xb7\xaf\xe8\xbf\x87\xe4\xb8\x8d\xe8\xa6\x81\xe9\x94\x99\xe8\xbf\x87\xef\xbc\x8c\xe8\xbf\x99\xe9\x87\x8c\xe6\x9c\x89\xe6\x9c\x80\xe5\xa5\xbd\xe7\x9a\x84\xe9\xb8\xa1\xe5\x84\xbf',
  'downloadUrl': 'app/com.ct.client/com.ct.client.apk',
  'iconUrl': 'app/com.ct.client/icon.jpg',
  'id': 1540629,
  'name': '\xe4\xb8\x8d\xe5\xad\x98\xe5\x9c\xa8\xe7\x9a\x84',
  'packageName': 'com.ct.client',
  'size': 4794202,
  'stars': 2}]

Вроде есть какой-то эффект, это действительно "артефакт".

Но ты скажи мне,\xe4\xbd\xa0\xe7\x9aЧто это за вещи? То, что должно было улучшить читаемость, теперь совершенно нечитаемо.

К счастью, я знаю некоторые кодировки в Python 2, и я знаю, что формат строки по умолчанию (без U) в Python 2 имеет тип STR, а также байты типа, который хранится в байтах.

Хорошо, кажется, я был неправ, я изменил его, используйте тип юникода для определения китайских строк.

>>> info = [{"id":1580615,"name":u"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":u"2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":u"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":u"斗鱼271934走过路过不要错过,这里有最好的鸡儿"}]
>>> 
>>> from pprint import pprint
>>> pprint(info)
[{'des': u'2011-2017\u4f60\u7684\u94c1\u5934\u5a03\u4e00\u76f4\u5728\u8fd9\u513f\u3002\u4e2d\u56fd\u6700\u5927\u7684\u5b9e\u540d\u5236SNS\u7f51\u7edc\u5e73\u53f0\uff0c\u5ae9\u5934\u9752',
  'downloadUrl': 'app/com.renren.mobile.android/com.renren.mobile.android.apk',
  'iconUrl': 'app/com.renren.mobile.android/icon.jpg',
  'id': 1580615,
  'name': u'\u76ae\u7684\u561b',
  'packageName': 'com.renren.mobile.android',
  'size': 21803987,
  'stars': 2},
 {'des': u'\u6597\u9c7c271934\u8d70\u8fc7\u8def\u8fc7\u4e0d\u8981\u9519\u8fc7\uff0c\u8fd9\u91cc\u6709\u6700\u597d\u7684\u9e21\u513f',
  'downloadUrl': 'app/com.ct.client/com.ct.client.apk',
  'iconUrl': 'app/com.ct.client/icon.jpg',
  'id': 1540629,
  'name': u'\u4e0d\u5b58\u5728\u7684',
  'packageName': 'com.ct.client',
  'size': 4794202,
  'stars': 2}]

Это действительно хорошо, но когда я вижу следующее, я теряю сознание. Откуда я знаю, что это за чертовщина? Не слишком ли я наивен? Когда я был компьютером?

u'\u6597\u9c7c271934\u8d70\u8fc7\u8def\u8fc7\u4e0d\u8981\u9519\u8fc7\uff0c\u8fd9\u91cc\u6709\u6700\u597d\u7684\u9e21\u513f'

В дополнение к этому, мы знаем, что строгие требования json должны использоватьДвойные кавычки, и когда я определял словарь, я также использовал двойные кавычки, почему он распечатывается?апостроф? Я слишком жесткий, я даже не могу контролировать свой собственный код?

На данный момент мы знаем две проблемы, связанные с pprint:

  1. Не удается нормально печатать на китайском языке под Python 2
  2. Невозможно вывести отформатированное содержимое в стандартном формате JSON (двойные кавычки)

2. Решить проблему

печатать китайский

Если вы используете его под Python 3, вы обнаружите, что китайский язык может отображаться нормально.

# Python3.7
>>> info = [{"id":1580615,"name":u"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":u"2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":u"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":u"斗鱼271934走过路过不要错过,这里有最好的鸡儿"}]
>>> 
>>> from pprint import pprint
>>> pprint(info)
[{'des': '2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青',
  'downloadUrl': 'app/com.renren.mobile.android/com.renren.mobile.android.apk',
  'iconUrl': 'app/com.renren.mobile.android/icon.jpg',
  'id': 1580615,
  'name': '皮的嘛',
  'packageName': 'com.renren.mobile.android',
  'size': 21803987,
  'stars': 2},
 {'des': '斗鱼271934走过路过不要错过,这里有最好的鸡儿',
  'downloadUrl': 'app/com.ct.client/com.ct.client.apk',
  'iconUrl': 'app/com.ct.client/icon.jpg',
  'id': 1540629,
  'name': '不存在的',
  'packageName': 'com.ct.client',
  'size': 4794202,
  'stars': 2}]
>>> 

Но часто (на некоторых серверах компании) вы не можете выбрать, какую версию Python использовать, я мог бы выбрать не потому, что есть лучшие альтернативы (я расскажу об этом позже).

Но из любопытства, разве я не написал статью о кодировании два дня назад? Я думаю, что я относительно хорошо разбираюсь в кодировании, поэтому я подумал о решении этой проблемы.

Просто посмотрите на исходный код pprint. Я действительно нашел решение. Если вы хотите оспорить его, остановитесь здесь и изучите, как реализовать его самостоятельно. Я считаю, что вам будет полезно прочитать исходный код.

Вот мое решение для справки:

Напишите свой собственный объект Printer, наследуемый от prettyprinter (PRINTER, используемый Pprint)

И перезаписать способ форматирования, чтобы определить, является ли объект входящего строкового типа типа STR. Если это не типа STR, а типа Unicode, кодируйте его в тип STR с UFT8.

# coding: utf-8
from pprint import PrettyPrinter

# 继承 PrettyPrinter,复写 format 方法
class MyPrettyPrinter(PrettyPrinter):
    def format(self, object, context, maxlevels, level):
        if isinstance(object, unicode):
            return (object.encode('utf8'), True, False)
        return PrettyPrinter.format(self, object, context, maxlevels, level)

info = [{"id":1580615,"name":u"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":u"2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":u"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":u"斗鱼271934走过路过不要错过,这里有最好的鸡儿"}]

MyPrettyPrinter().pprint(info)

Вывод следующий, проблема с отображением китайского языка решена:

печатать двойные кавычки

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

При создании экземпляра объекта PrettyPrinter вы можете получить объект потока, который указывает, куда вы хотите вывести содержимое.По умолчанию используется поток sys.stdout, который является стандартным выводом.

Теперь мы хотим изменить содержимое вывода, то есть заменить одинарные кавычки вывода двойными кавычками.

Затем мы можем сами определить объект типа stream.Этому объекту не нужно наследовать какой-либо родительский класс, пока вы реализуете метод записи.

С идеей вы можете начать писать код следующим образом:

# coding: utf-8
from pprint import PrettyPrinter

class MyPrettyPrinter(PrettyPrinter):
    def format(self, object, context, maxlevels, level):
        if isinstance(object, unicode):
            return (object.encode('utf8'), True, False)
        return PrettyPrinter.format(self, object, context, maxlevels, level)

class MyStream():
    def write(self, text):
        print text.replace('\'', '"')

info = [{"id":1580615,"name":u"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":u"2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":u"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":u"斗鱼271934走过路过不要错过,这里有最好的鸡儿"}]
MyPrettyPrinter(stream=MyStream()).pprint(info)

Попробуй его исполнить, боже мой, как это так.

[
{
"des"
: 
2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青
,
  "downloadUrl": 
"app/com.renren.mobile.android/com.renren.mobile.android.apk"
,
  "iconUrl": 
"app/com.renren.mobile.android/icon.jpg"
,
  "id": 
1580615
,
  "name": 
皮的嘛
,
  "packageName": 
"com.renren.mobile.android"
,
  "size": 
21803987
,
  "stars": 
2
}
,
 
{
"des"
: 
斗鱼271934走过路过不要错过,这里有最好的鸡儿
,
  "downloadUrl": 
"app/com.ct.client/com.ct.client.apk"
,
  "iconUrl": 
"app/com.ct.client/icon.jpg"
,
  "id": 
1540629
,
  "name": 
不存在的
,
  "packageName": 
"com.ct.client"
,
  "size": 
4794202
,
  "stars": 
2
}
]

После некоторых исследований я обнаружил, что это связано с тем, что функция печати по умолчанию добавляетновая линия.

Итак, как сделать так, чтобы содержимое, напечатанное функцией печати, не переносилось?

Метод очень прост, но я считаю, что многие люди не знают, просто добавьте печать после содержаниязапятаяПросто сделай это.

Как показано ниже.

Знайте проблему, а затем модифицируйте код

# coding: utf-8
from pprint import PrettyPrinter

class MyPrettyPrinter(PrettyPrinter):
    def format(self, object, context, maxlevels, level):
        if isinstance(object, unicode):
            return (object.encode('utf8'), True, False)
        return PrettyPrinter.format(self, object, context, maxlevels, level)

class MyStream():
    def write(self, text):
        print text.replace('\'', '"'),

info = [{"id":1580615,"name":u"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":u"2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":u"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":u"斗鱼271934走过路过不要错过,这里有最好的鸡儿"}]

MyPrettyPrinter(stream=MyStream()).pprint(info)

Наконец удалось, это было непросто.

3. Зачем беспокоиться

После некоторого метания выше, я, наконец, осознал своюжеланныйспрос.

Цена в том, что мне потребовалось два полных часа, чтобы понять это, и для Сяобая у меня может не хватить уверенности и терпения, чтобы сделать такое.

Итак, что я хочу сказать, так это то, что pprint под Python 2 действительно больше не используется..

Почему я это говорю, ведь есть заведомо лучшие альтернативы, а жизнь слишком коротка. Раз используется Python, конечно, просто и легко. Класс, не напрасно ли? (Я ругаю себя?

Если вы готовы отказаться от pprint, то я рекомендую использовать json.dumps, и я обещаю, что вы больше никогда не захотите использовать pprint.

печатать китайский

На самом деле, невозможно печатать китаец, что является большой ямой, привлеченной Python 2, и он не полон PPRINT.

Но та же проблема, в json.dumps просто добавить параметр, что не шибко проще pprint.

Конкретный пример кода выглядит следующим образом:

>>> info = [{"id":1580615,"name":"皮的嘛","packageName":"com.renren.mobile.android","iconUrl":"app/com.renren.mobile.android/icon.jpg","stars":2,"size":21803987,"downloadUrl":"app/com.renren.mobile.android/com.renren.mobile.android.apk","des":"2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青"},{"id":1540629,"name":"不存在的","packageName":"com.ct.client","iconUrl":"app/com.ct.client/icon.jpg","stars":2,"size":4794202,"downloadUrl":"app/com.ct.client/com.ct.client.apk","des":"斗鱼271934走过路过不要错过,这里有最好的鸡儿"}]
>>> 
>>> import json
>>> 
>>> 
>>> print json.dumps(info, indent=4, ensure_ascii=False)
[
    {
        "downloadUrl": "app/com.renren.mobile.android/com.renren.mobile.android.apk", 
        "iconUrl": "app/com.renren.mobile.android/icon.jpg", 
        "name": "皮的嘛", 
        "stars": 2, 
        "packageName": "com.renren.mobile.android", 
        "des": "2011-2017你的铁头娃一直在这儿。中国最大的实名制SNS网络平台,嫩头青", 
        "id": 1580615, 
        "size": 21803987
    }, 
    {
        "downloadUrl": "app/com.ct.client/com.ct.client.apk", 
        "iconUrl": "app/com.ct.client/icon.jpg", 
        "name": "不存在的", 
        "stars": 2, 
        "packageName": "com.ct.client", 
        "des": "斗鱼271934走过路过不要错过,这里有最好的鸡儿", 
        "id": 1540629, 
        "size": 4794202
    }
]
>>> 

Есть два ключевых параметра json.dumps:

  • indent=4: Отступ единицы с 4 пробелами
  • ensure_ascii=False: получать символы, не закодированные в ASCII, чтобы можно было использовать китайский язык.

Можно сказать, что по сравнению с pprint json.dumps является победителем:

  1. Два параметра могут удовлетворить все мои потребности (печатать китайский язык и двойные кавычки)
  2. Даже под Python 2 не обязательно использовать китайскийu'中文'этот способ написания
  3. Python2 и Python3 написаны совершенно одинаково, и для этого нет необходимости рассматривать вопросы совместимости.

4. Подведите итоги

Первоначально очень простая точка зрения, я понимаю, насколько трудно доказать PPRINT, эти два требования потратили много времени для изучения исходного кода PPRINT (различные процедуры, но все еще довольно сложно), но хорошие новости могут быть последняя награда.

Обмен этой статьей находится здесь После прочтения этой статьи, я думаю, вы можете получить три очка знаний

  1. Основная мысль: больше не используйте pprint в Python 2.
  2. Если вы действительно хотите его использовать и у вас такие же требования к преобразованию, вы можете обратиться к моей реализации
  3. Запятую можно добавить после оператора печати в Python 2.

над. Надеюсь, эта статья поможет вам.

关注公众号,获取最新干货!