4

i have created a python Ordered Dictionary by importing collections and stored it in a file named 'filename.txt'. the file content looks like

OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3)])

i need to make use of this OrderedDict from another program. i do it as

myfile = open('filename.txt','r')
mydict = myfile.read()

i need to get 'mydict' as of Type

<class 'collections.OrderedDict'>

but here, it comes out to be of type 'str'.
is there any way in python to convert a string type to OrderedDict type? using python 2.7

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
srek
  • 313
  • 2
  • 4
  • 9
  • I don't have a good answer (ie. not using `eval`) to your question but you really shouldn't be storing it like that. – jamylak May 08 '12 at 12:46
  • Don't store your data like that. At least use a Pickle. I will downvote any answers that suggest using `eval()` – John La Rooy May 08 '12 at 12:47
  • The reasons why people are afraid of `eval` are essentially religious rather than rational. Every language construct exists for a reason and there's no need to invent something complicated when one single `eval(x)` does the trick. Yes, it should be used with caution (like any other thing), but as long as data comes from a trusted source, using `eval` is just fine. – georg May 08 '12 at 13:21
  • @thg435 Well, since we don't know if the data is from a trusted source, that's a big step to make. Even if it does, why use an ugly, slow, *potentially* dangerous, hard to debug method when there are plenty of better methods. The real issue here is how the data is being stored, and storing it in another format has other advantages (like what if you need the data in something other than Python?). – Gareth Latty May 08 '12 at 20:14
  • @Lattyware: the eval debate is tired to say the best. Just like with "goto" decades ago, people seem to develop some kind of irrational fear of it. Most of us think of it as evil per se and believe that just writing it once would put an eternal curse on their code and even their lives. This appears to be some kind of religion, and as such has no business in the rational world of computer programming. – georg May 08 '12 at 20:59
  • @thg435 And just like with `goto` it's not something that you should ever *need* to use in a modern language like Python. It's there because there are use cases and for your 2 minute program to do x, y or z - who cares, but beyond that, it should always come with health warnings. – Gareth Latty May 08 '12 at 21:05
  • @Lattyware: just out of interest, try grepping "eval" in your python folder. For me, `find "/System/Library/Frameworks/Python.framework" -name "*.py" | xargs grep "eval(" | wc -l` prints "1212", so yes, it does have uses. Regarding "goto" and "modern languages", it might be interesting for you to read this [classic discussion](http://kerneltrap.org/node/553/2131). – georg May 08 '12 at 21:14
  • @thg435 Yeah, and that's an example you can use `goto` in a reasonable way, but it's a lot easier to do bad things with it, so why bother when there are better ways to do things? I have the same thought process with `eval()` - I can always do it a different way, and I have yet to find a case where it made more sense overall to use `eval()` over the alternative. There are always too many reasons to do it the other way. – Gareth Latty May 08 '12 at 21:18

4 Answers4

7

You could store and load it with pickle

import cPickle as pickle

# store:
with open("filename.pickle", "w") as fp:
    pickle.dump(ordered_dict, fp)

# read:
with open("filename.pickle") as fp:
    ordered_dict = pickle.load(fp)

type(ordered_dict) # <class 'collections.OrderedDict'>
wong2
  • 34,358
  • 48
  • 134
  • 179
6

The best solution here is to store your data in a different way. Encode it into JSON, for example.

You could also use the pickle module as explained in other answers, but this has potential security issues (as explained with eval() below) - so only use this solution if you know that the data is always going to be trusted.

If you can't change the format of the data, then there are other solutions.

The really bad solution is to use eval() to do this. This is a really really bad idea as it's insecure, as any code put in the file will be run, along with other reasons

The better solution is to manually parse the file. The upside is that there is a way you can cheat at this and do it a little more easily. Python has ast.literal_eval() which allows you to parse literals easily. While this isn't a literal as it uses OrderedDict, we can extract the list literal and parse that.

E.g: (untested)

import re
import ast
import collections

with open(filename.txt) as file:
    line = next(file)
    values = re.search(r"OrderedDict\((.*)\)", line).group(1)
    mydict = collections.OrderedDict(ast.literal_eval(values))
Community
  • 1
  • 1
Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • 1
    +1, would be +2 if it were two things: a) possible, and b) more clearly marked that "the really bad solution" is actually "**pure evil**" – Chris Pfohl May 08 '12 at 12:49
  • Nice solution to the current problem, I was thinking the same thing. – jamylak May 08 '12 at 12:53
  • 2
    @Cpfohl, c) if +2 were possible – John La Rooy May 08 '12 at 12:53
  • 1
    @gnibbler: see `a` ;-)...Oops... SYNTAX ERROR 1450 AMBIGUOUS PARSING – Chris Pfohl May 08 '12 at 12:55
  • Interestingly enough, the comments on your [link](http://stackoverflow.com/a/1832957/989121) prove quite the contrary, namely, there's nothing wrong about eval. – georg May 08 '12 at 13:31
  • @thg435 There is not 'nothing wrong about eval' - it's a horrible way of getting things done, and there are much better ways to do it, and I gave two good ways in my answer. The comments merely point out that eval won't destroy the world, they do **not** prove it's secure, or a good solution to a problem like this. – Gareth Latty May 08 '12 at 19:33
  • @Lattyware: you solution is good, except that it's 200+ bytes long, while `x=eval(x)` is only 9. – georg May 08 '12 at 19:44
  • @thg435 Well, that depends on the solution. Encoding to and decoding as JSON (the best way) would be shorter than that, but regardless, the point is that being short is not the most important thing. – Gareth Latty May 08 '12 at 20:11
  • This should be the accepted answer because while pickling or changing to some other output would be better, in many cases someone may not have access to/permission to change the source, or simply can't/not want to run the code again (if it is some long process or the input data is gone), and this provides more than one solution with the OP's question "as-is" – physincubus Mar 15 '19 at 06:06
0

This is not a good solution but it works. :)

#######################################
# String_To_OrderedDict
# Convert String to OrderedDict
# Example String
#    txt = "OrderedDict([('width', '600'), ('height', '100'), ('left', '1250'), ('top', '980'), ('starttime', '4000'), ('stoptime', '8000'), ('startani', 'random'), ('zindex', '995'), ('type', 'text'), ('title', '#WXR#@TU@@Izmir@@brief_txt@'), ('backgroundcolor', 'N'), ('borderstyle', 'solid'), ('bordercolor', 'N'), ('fontsize', '35'), ('fontfamily', 'Ubuntu Mono'), ('textalign', 'right'), ('color', '#c99a16')])"
#######################################
def string_to_ordereddict(txt):

    from collections import OrderedDict
    import re

    tempDict = OrderedDict()

    od_start = "OrderedDict([";
    od_end = '])';

    first_index = txt.find(od_start)
    last_index = txt.rfind(od_end)

    new_txt = txt[first_index+len(od_start):last_index]

    pattern = r"(\(\'\S+\'\,\ \'\S+\'\))"
    all_variables = re.findall(pattern, new_txt)

    for str_variable in all_variables:
        data = str_variable.split("', '")
        key = data[0].replace("('", "")
        value = data[1].replace("')", "")
        #print "key : %s" % (key)
        #print "value : %s" % (value)
        tempDict[key] = value

    #print tempDict
    #print tempDict['title']

    return tempDict
Guray Celik
  • 1,281
  • 1
  • 14
  • 13
0

Here's how I did it on Python 2.7

from collections import OrderedDict
from ast import literal_eval

# Read in string from text file
myfile = open('filename.txt','r')
file_str = myfile.read()

# Remove ordered dict syntax from string by indexing
file_str=file_str[13:]
file_str=file_str[:-2]

# convert string to list
file_list=literal_eval(file_str)

header=OrderedDict()
for entry in file_list:
    # Extract key and value from each tuple
    key, value=entry
    # Create entry in OrderedDict
    header[key]=value

Again, you should probably write your text file differently.