0

If you convert an object/list to string with ascii and than back with eval you get the same representation with same bytes size.
Why ast.literal_eval give back an object with different size?

a = [{"a": {"b": False}, True: 1}, 2, (3,6), ('g',),{"jfg"}]
b = ascii(a)
c = eval(b)
d = ast.literal_eval(b)
print(f"a: {sys.getsizeof(a)}\t{type(a)}\t{a}\nb: {sys.getsizeof(b)}\t{type(b)}\t{b}\nc: {sys.getsizeof(c)}\t{type(c)}\t{c}\nd: {sys.getsizeof(d)}\t{type(d)}\t{d}")
a: 96   <class 'list'>  [{'a': {'b': False}, True: 1}, 2, (3, 6), ('g',), {'jfg'}]
b: 107  <class 'str'>   [{'a': {'b': False}, True: 1}, 2, (3, 6), ('g',), {'jfg'}]
c: 96   <class 'list'>  [{'a': {'b': False}, True: 1}, 2, (3, 6), ('g',), {'jfg'}]
d: 120  <class 'list'>  [{'a': {'b': False}, True: 1}, 2, (3, 6), ('g',), {'jfg'}]

Which is the better/safer/faster/lighter way to convert an object to string and back?

supermodo
  • 675
  • 6
  • 15
  • 2
    The size of a list can depend on the specific functions that were used to create it, because of the way it grows dynamically as elements are added. – Barmar Mar 19 '21 at 16:21
  • Just compare: `sys.getsizeof(eval('[13]'))` to `sys.getsizeof(ast.literal_eval('[13]'))` – Barmar Mar 19 '21 at 16:24
  • @Barmar you mean that `literal_eval` is adding elements to the list and `eval` don't? – supermodo Mar 19 '21 at 21:14
  • Maybe. You'd have to look at the source code to see precisely how they work. – Barmar Mar 19 '21 at 21:16
  • `literal_eval()` may be written in Python so it constructs the list incrementally, while `eval()` is a built-in that can make use of internal functions to create a list with a specified size. – Barmar Mar 19 '21 at 21:17

1 Answers1

0

In the grand theme of things, it is not related to ast.literal_eval.

Python lists are dynamic. They can grow and shrink.

You create the list using a literal list object (ie a) the runtime knows exactly how much memory it needs to allocate.

When you create the list in any other method, it is hard to predict how big the list is eventually going to be, so the runtime allocates memory using a specific algorithm, to make sure that memory is not wasted but on the other hand, tries to not re-allocate memory too frequently since that is not efficient.

You can reproduce the same behavior by simplifying the example. For example, creating an empty list then extending it:

import sys

literal_list = [{"a": {"b": False}, True: 1}, 2, (3,6), ('g',),{"jfg"}]
print(f"a: {sys.getsizeof(literal_list)}\t{type(literal_list)}\t{literal_list}")
li = []
li.extend([{"a": {"b": False}, True: 1}, 2, (3,6), ('g',),{"jfg"}])
print(f"li: {sys.getsizeof(li)}\t{type(li)}\t{li}")

outputs

a: 48   <class 'list'>  [{'a': {'b': False}, True: 1}, 2, (3, 6), ('g',), {'jfg'}]
li: 60  <class 'list'>  [{'a': {'b': False}, True: 1}, 2, (3, 6), ('g',), {'jfg'}]
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • Why your say that your example is simplifying mine? I don't intentionally modify `b`. Do `literal_eval` modify the list somehow and `eval` don't? – supermodo Mar 19 '21 at 20:53