1

Essentially, I want to print a dictionary such that it uses str() instead of repr() to stringify its keys and values.

This would be especially useful when saving a traceback string in some json. But this appears to be much more difficult than I would imagine:

In [1]: import pprint, json

In [2]: example = {'a\tb': '\nthis\tis\nsome\ttext\n'}

In [3]: print(example)
{'a\tb': '\nthis\tis\nsome\ttext\n'}

In [4]: str(example)
Out[4]: "{'a\\tb': '\\nthis\\tis\\nsome\\ttext\\n'}"

In [5]: pprint.pprint(example)
{'a\tb': '\nthis\tis\nsome\ttext\n'}

In [6]: pprint.pformat(example)
Out[6]: "{'a\\tb': '\\nthis\\tis\\nsome\\ttext\\n'}"

In [7]: json.dumps(example, indent=2)
Out[7]: '{\n  "a\\tb": "\\nthis\\tis\\nsome\\ttext\\n"\n}'

In [8]: print(json.dumps(example, indent=2))
{
  "a\tb": "\nthis\tis\nsome\ttext\n"
}

The behaviour I want (and expect) is this:

> print(d)
{'a    b': '
this    is
some    text
'}

> pprint.pprint(d)
{
  'a    b': '
this    is
some    text
'
}

or maybe, if pprint were really smart:

> pprint.pprint(d)
{
  'a    b': '
  this    is
  some    text
  '
}

...but I can't seem to built-in way to do this!

I'd like to know what the standard/best way to do this is, and if there isn't one, why not? Is there a special reason that repr() is always called on strings instead of str() when printing dicts (and other containers)?

mavix
  • 2,488
  • 6
  • 30
  • 52

2 Answers2

1

more general answer:

def myPrint(txt)
    print(bytes(str(txt), 'utf-8').decode("unicode_escape"))

myPrint(example)

{'a b': '
this    is
some    text
'}

Playing with this a bit more:

NOTE It's generally a bad idea to overwrite built-ins, and this might cause other problems, but.......

import builtins

def print(*args, literal = False):
        if literal:
            builtins.print(bytes(str(" ".join([str(ag) for ag in args])), 'utf-8').decode("unicode_escape"))
        else:
            builtins.print(*args)

print(example, literal = True)
{'a b': '
this    is
some    text
'}

print(example)
{'a\tb': '\nthis\tis\nsome\ttext\n'}

print(example, literal = False)
{'a\tb': '\nthis\tis\nsome\ttext\n'}
Schalton
  • 2,867
  • 2
  • 32
  • 44
0

You could make this more generic but it'l work for \n and \t as is

example = {'a\tb': '\nthis\tis\nsome\ttext\n'}

def myPrint(txt):
    txt = str(txt)
    swaps = [("\\n", "\n"),
             ("\\t", "\t")]
    for swap in swaps:
        txt= txt.replace(swap[0], swap[1])
    print(txt)

myPrint(example)

{'a b': '
this    is
some    text
'}
Schalton
  • 2,867
  • 2
  • 32
  • 44
  • your desired output starts with a \n which you could hard code in, it was unclear if you forgot it in your example variable or if you wanted it built in -- easy enough to check if \n is in the beginning and end of the string and add it if it isnt – Schalton Sep 02 '18 at 19:05
  • 1
    a more succinct version of what you wrote might be: `print(str(example).replace('\\n', '\n').replace('\\t', '\t'))` – mavix Sep 02 '18 at 19:08
  • @Timir I think that's only for Python 2 – Schalton Sep 02 '18 at 19:12
  • Timir, that 'works' just had to convert the string to bytes first, see my second answer – Schalton Sep 02 '18 at 19:31