Parse String into namedtuple object - python

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.

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:
Create your own method that parses a string of the format "Range(key= ...(etc.)", OR
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

How can I transform my dict in Json object?

I'm new in Python, and I'm trying to encode in Json an data dict.
My dict is :
data = { ('analogInput', 18) : [('objectName','AI8-Voltage'),
('presentValue',238.3),
('units','Volts')],
('analogInput', 3) : [('objectName','AI3-Pulse'),
('presentValue',100),
('units','Amp')]
}
And when i'm trying to do : foo = json.dumps(data)
I've got this message : Fatal error : keys must be str, int, float, bool or None, not tuple
I'm trying to search answers, but I dont understand how i can do proceed in my case
Thanx you any answers
First of all, not all types can be used for JSON keys.
Keys must be strings, and values must be a valid JSON data type (string, number, object, array, Boolean or null).
For more information, take a look at this.
Now as feasible solution, I recommend you to implement two functions that converts your tuples to string and converts your strings to tuple. A quite simple example is provided below:
import json
data = { ('analogInput', 18) : [('objectName','AI8-Voltage'),
('presentValue',238.3),
('units','Volts')],
('analogInput', 3) : [('objectName','AI3-Pulse'),
('presentValue',100),
('units','Amp')]
}
def tuple_to_str(t):
# It can be implemeneted with more options
return str(t[0])+'_'+str(t[1])
def str_to_tuple(s):
l =s.split('_')
# Your first (second) item is int
l[1] = int(l[1])
return tuple(l)
if __name__=="__main__":
# create a space for a dict of data with string keys
s_data= dict()
for key in data:
s_data[tuple_to_str(key)] = data[key]
x = json.dumps(s_data)
# create a space to load the json with string keys
raw_data = json.loads(x)
final_data = dict()
for key in raw_data:
final_data[str_to_tuple(key)] = raw_data[key]
# Ture
print(final_data)
The error is explicit. In a Python dict, the key can be any hashable type, including a tuple, a frozen set or a frozen dict (but neither a list, nor a set or a dict).
But in a Json object, dictionary keys can only be strings, numbers (int, or float), booleans or the special object None.
Long story short, your input dictionary cannot be directly converted to Json.
Possible workarounds:
use an different serialization tool. For example, pickle can accept any Python type, but is not portable to non Python application. But you could also use a custom serialization format, if you write both the serialization and de-serialization parts
convert the key to a string. At deserialization time, you would just have to convert the string back to a tuple with ast.literal_evel:
js = json.dumps({str(k): v for k,v in data.items()})
giving: {"('analogInput', 18)": [["objectName", "AI8-Voltage"], ["presentValue", 238.3], ["units", "Volts"]], "('analogInput', 3)": [["objectName", "AI3-Pulse"], ["presentValue", 100], ["units", "Amp"]]}
You can load it back with:
data2 = {ast.literal_eval(k): v for k,v in json.loads(js).items()}
giving {('analogInput', 18): [['objectName', 'AI8-Voltage'], ['presentValue', 238.3], ['units', 'Volts']], ('analogInput', 3): [['objectName', 'AI3-Pulse'], ['presentValue', 100], ['units', 'Amp']]}
You can just see that the json transformation has changed the tuples into lists.

what is difference betwen string and tuple?

Can anyone explain what is difference between string and tuple
a="string"
b=("s","t","r","i","n","g")
both are immutable.
They're different types.
"str" in a # True
("s", "t", "r") in b # False
Which means they have different methods, different use cases, different meanings, different implementations, etc. etc. etc.... Consider:
datapoint_tuple = (datetime.datetime.now(), 42)
datapoint_str = ...???
Essentially the only thing they have in common is their immutability.
Strings are immutable in python which means it cannot be changed once created, if you want to update it then a new string is to be created for example.
s="Abcdef"
c=s+'112'
print s,c
you can extract value using index, find values but cannot modify it
To access substrings, use the square brackets for slicing along with the index or indices to obtain your substring
Tuple they are immutable like strings and sequence like lists.They are used to store data just like list, just like string you cannot update or edit the tuple to change it you have to create a new one just like strings.Tuples can be created using parenthesis () and data is inserted using comas.
t1=(1,2,3,'hi')
print type(t1)
print t1
A string is a sequence of unicode characters with quotation marks on either side of the sequence.
Example: mystring = "this is a string"
A tuple is an ordered sequence of objects or characters separated by commas with parentheses on either side of the sequence.
Example: mytuple = (7, "u", "p", 1, "e')
They are, however, similar in the fact that they are both immutable
t1 = (1,2,3,4)
t2 =(1,2,3,4)
print( t1 is t2)
Output: True
This means they refer to the same object and string does the same thing. But tuples comes into play when few data need to stay together. For example: file name, it's size and type. Even when you return multiple values they are returned as a tuple.
def convert_seconds(seconds):
hours = seconds//3600
minutes = (seconds - hours*3600)//60
remaining_seconds = seconds- hours*3600 - minutes*60
return hours,minutes,remaining_seconds
result = convert_seconds(5000)
print(type(result))
output: <class 'tuple'>
Once you know why using it, it will clear your confusion.
tuple use a trailing comma:
tuple_a = 'a',
print(type(tuple_a)) # <class 'tuple'>
string don't use:
string_a = 'a'
print(type(string_a)) # <class 'str'>
but string and tuple has some same characteristics。
eg:
1、indexing and slicing
string_same = 'string'
tuple_same = ('s', 't', 'r', 'i', 'n', 'g')
print(string_same[0], tuple_same[0]) # s s
print(string_same[:-1], tuple_same[:-1]) # strin ('s', 't', 'r', 'i', 'n')
2、Immutability
means string and tuple not suport item assigment
string_same[0] = 'python_'
tuple_same[0] = 'python_'
TypeError: 'str' object does not support item assignment
TypeError: 'tuple' object does not support item assignment
you could find all of the diffrent from the Doc.
including other tyeps build-in types.
https://docs.python.org/3/library/stdtypes.html?highlight=tuple#tuple

how to create a dictionary from a set of properly formatted tuples in python

Is there a simple way to create a dictionary from a list of formatted tuples. e.g. if I do something like:
d={"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}
This creates a dictionary called d. However, if I want to create a dictionary from a string which contains the same string, I can't do that
res=<some command that returns {"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}>
print res
# returns {"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}
d=dict(res)
This throws an error that says:
ValueError: dictionary update sequence element #0 has length 1; 2 is required
I strongly strongly suspect that you have json on your hands.
import json
d = json.loads('{"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}')
would give you what you want.
Use dict(zip(tuples))
>>> u = ("foo", "bar")
>>> v = ("blah", "zoop")
>>> d = dict(zip(u, v))
>>> d
{'foo': 'blah', 'bar': 'zoop'}
Note, if you have an odd number of tuples this will not work.
Based on what you gave is, res is
# returns {"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}
So the plan is to grab the string starting at the curly brace to the end and use json to decode it:
import json
# Discard the text before the curly brace
res = res[res.index('{'):]
# Turn that text into a dictionary
d = json.loads(res)
All you need to do in your particular case is
d = eval(res)
And please keep security in mind when using eval, especially if you're mixing it with ajax/json.
UPDATE
Since others pointed out you might be getting this data over the web and it isn't just a "how to make this work" question, use this:
import json
json.loads(res)

How can I parse a dictionary string?

I am trying to convert a string to a dictionary with dict function, like this
import json
p = "{'id':'12589456'}"
d = dict(p)
print d['id']
But I get the following error
ValueError: dictionary update sequence element #0 has length 1; 2 is required
Why does it fail? How can I fix this?
What you have is a string, but dict function can only iterate over tuples (key-value pairs) to construct a dictionary. See the examples given in the dict's documentation.
In this particular case, you can use ast.literal_eval to convert the string to the corresponding dict object, like this
>>> p = "{'id':'12589456'}"
>>> from ast import literal_eval
>>> d = literal_eval(p)
>>> d['id']
'12589456'
Since p is a string containing JSON (ish), you have to load it first to get back a Python dictionary. Then you can access items within it:
p = '{"id":"12589456"}'
d = json.loads(p)
print d["id"]
However, note that the value in p is not actually JSON; JSON demands (and the Python json module enforces) that strings are quoted with double-quotes, not single quotes. I've updated it in my example here, but depending on where you got your example from, you might have more to do.

Python compiled eval?

my situation is as follows:
I have a large table like object which is accessed with a string key and integer index; i.e. lookup is like this: value = table.get("Key", index) .
I would like to give the user the opportunity to enter an arbitrary algebraic expression involving the string keys. The code code should then iterate over the second index and evaluate the expression repeatedly.
So for user input like this: "KeyA + 2*math.abs(KeyC)" I would like to run python code resembling:
for index in index_list:
answer = table.get("KeyA", index) + 2*math.abs(table.get("Keyc",index))
I guess can parse the expression using one of the Python Parser libraries I found on the internet, but it is not by any means clear to me how actually "run" the parsed code. Any suggestions?
If your end users can enter variables in figure brackets, {..}, you can use str.format to format your string
>>> expression = '{a}*{b}'
>>> values = {'a': 10, 'b': 20, 'c': 30}
>>> expression.format(**values)
'10*20'
Here values dictionary might be filled with table.get for all keys found in expression, for example with a regular expression:
>>> import re
>>> regexp = re.compile('{(.*?)}')
>>> keys = regexp.findall(expression)
>>> keys
['a', 'b']
>>> table_get = lambda *x: np.random.randint(5)
>>> values = {k: table_get(k) for k in keys}
>>> expression.format(**values)
'1*4'
Then you can refer to Safe way to parse user-supplied mathematical formula in Python for safe expression parsing and evaluation.

Categories