Home > Software design >  Parse String into namedtuple object
Parse String into namedtuple object

Time:08-18

How to read back string, into namedtuple?

import collections
from typing import Sequence, Iterator
import ast

Range = collections.namedtuple("Range", ["key", "min", "max", "in_range" ])

Ranges to string

Test object to string:

r1 = tools.Range(key='T1',min=-0.01,max=0.19, in_range=True)
r2 = tools.Range(key='T2',min=2,max=10, in_range=False)
r3 = tools.Range(key='T3',min=225000,max=1583515.5, in_range=True)
rs = [r1, r2, r3]
rstr = str(rs)
print(rstr) 
# output:
# [Range(key='T1', min=-0.01, max=0.19, in_range=True), Range(key='T2', min=2, max=10, in_range=False), Range(key='T3', min=225000, max=1583515.5, in_range=True)]

How to read same or similar string now into object (list of Range)?

Parse back String to Ranges

What I've tried with most hope of success:

source_string = "[Range(key='T1', min=-0.01, max=0.19, in_range=True), Range(key='T2', min=2, max=10, in_range=False), Range(key='T3', min=225000, max=1583515.5, in_range=True)]"
source = ast.literal_eval(source_string)
ranges = tools.Range(key=source["key"],min=float(source["min"]), max=float(source["max"]), in_range=bool(source["in_range"]))

I did also variants, with no success. I am open to change the string syntax to get the ranges object generate.

CodePudding user response:

The ast.literal_eval function can only parse the following types:

  • strings
  • bytes
  • numbers
  • tuples
  • lists
  • dicts
  • sets
  • booleans
  • None and Ellipsis

This also means that it can only parse a tuple, list, dict, or set containing these specific types. It cannot parse a list of namedtuple objects. So you will have to either:

  1. Create your own method that parses a string of the format "Range(key= ...(etc.)", OR
  2. Remove the attribute names/keywords from your string, leaving simply a tuple for each element. You can then use python's built-in map function in combination with the namedtuple._make method to parse the list of tuples:
source_string = "[('T1', -0.01, 0.19, True), ('T2', 2, 10, False), ('T3', 225000, 1583515.5, True)]"
source = ast.literal_eval(source_string)
ranges = list(map(Range._make, source))

If you really need Range(...) and/or key=..., min=... to be a part of the string, you could potentially pre-process the string using regex.

  • Related