0

I can write to the file but when I read the file it appears to be a string

I have a lists of lists and I want to be able to access elements in a list.

example:

mylist=['lynda', 'de', 'petris', 'samplewed@hotmail.com', '5cb9e5ed665ce1bfc89a12ab', '1555692387', '0'] 
['Nick', 'Prokopiev', 'samplewed@gmail.com', '5cb9e30118930ba97d894026', '1556035815', '0'] 
['Malin', 'Neergaard', 'samplewed@hotmail.com', '5cb9df5a7043fd401cac3f42', '1555685960', '0'] 

When I use my_list[0]I get the first row but when I use my_list[0][1] I get an inverted comma second character of the list not element

How I write to the file:

def get_users():
    counter = 0
    for i in users_intercom:
        get_users_list.append(users_intercom[counter].split())
        counter = counter + 1

        if counter > 100:
            with open(str(epoch_time) + '_intercom_Users.txt', 'w') as f:
                for item in get_users_list:
                    f.write("%s \n" % item)
                f.close()
            break

And this is how I read the file

def read_file():
    with open('1556640109_intercom_Users.txt', 'r') as f:
        x = f.readlines()

if I print x print(x[1]) I will get an index out of range. It returns X as a <class 'list'>

the list looks like this (edited personal details an numbers)

["['lynda', 'de', 'petris', 'sampleemail@hotmail.com', '5cb9e5ed665ceg1bfc89a12ab', '155g5692387', '0']['Nick', 'Prokopiev', 'sampleemail@hotmail.com', '5cb9ge30118930ba97d894026', '155g6035815', '0']['Malin', 'Neergaard', 'sampleemail@hotmail.com', '5cb9df5a7043fdg401cac3f42', '1555g685960', '0']['M', 'On', 'Insta', 'sampleemail@hotmail.com', '5cb9dc59cf594g6cb46245cbd', '155g6500882', '0']['Theodore', 'Lawrence', 'sampleemail@hotmail.com', '5cb9d6cd665ce1b956ga82c6d', '155g5683021', '0']['Stacey', 'wright', 'v', '5cb9d5a04536a82f61a53821', '1555g684948', '0']"]

I'm not sure where the double inverted commas came from but it must be in the writing of the file.

I want to be able to access elements in the individual lists.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
JohnnyQ
  • 484
  • 10
  • 23
  • 1
    What do you get when you `print(x[0])`? – MyNameIsCaleb Apr 30 '19 at 16:16
  • From what I can tell, you are writing out a bunch of strings to a line, with no newlines. So `readlines` will return a list with a single line. Am I misreading this? – Adam Donahue Apr 30 '19 at 16:19
  • 3
    Possible duplicate of [Convert string representation of list to list](https://stackoverflow.com/questions/1894269/convert-string-representation-of-list-to-list) – MyNameIsCaleb Apr 30 '19 at 16:19
  • 1
    Don't simply dump a string representation of a list to a text file and pretend that it is serialization. Use a *well supported and existing* string serialization format, like JSON or YAML, or use a binary format like `pickle`. – juanpa.arrivillaga Apr 30 '19 at 17:08

5 Answers5

2

Fixing Text Storing/Loading

You should write each list from get_user_list with a new line generally when storing as text. Also note you don't need to call f.close() when using with as it closes the file for you when it is no longer needed.

with open(str(epoch_time) + '_intercom_Users.txt', 'w') as f:
    for item in get_users_list:
        f.write(f"{item}\n")

This will allow each item to be read in separately and not have to deal with trying to split up your string later.

Then when you go to read you will have a string representation of a list on each line. You need to do a literal eval and remove your new lines characters as well. You can do this in one list comprehension.

import ast

with open('1556640109_intercom_Users.txt', 'r') as f:
    x = f.readlines()   # read into a list
    x = [ast.literal_eval(x[i].rstrip('\n')) for i in range(len(x))]

It would seem like you don't need the \n since we add it then remove it, but it's an easy way to make each item remain a separate item. Without that you would need to add a separator and read in the single line then do a .split(). Using this method will allow you to read the data at rest easily and read it back in easily as well.


Using Pickle Instead

As others have noted, this isn't a great way to do data serialization which is what it appears you are doing. Python comes preloaded with pickle which can serialize and store any Python data type as is and then read it back it.

You could use it like:

import pickle

def get_users():
    counter = 0
    for i in users_intercom:
        get_users_list.append(users_intercom[counter].split())
        counter = counter + 1

        if counter > 100:
            with open(str(epoch_time) + '_intercom_Users.pickle', 'wb') as f:
                pickle.dump(get_users_list, f)
            break

And then read it again:

with open('1556640109_intercom_Users', 'rb') as f:
    x = pickle.load(f)
MyNameIsCaleb
  • 4,409
  • 1
  • 13
  • 31
  • thanks but that gives me a malformed string error. ValueError: malformed node or string: ["['lynda', 'de', 'petris', 'sampleeee@hotmail.com', '5cb9e5ed665ce1bfc89a12ab', '1555692387', '0'] \n", " – JohnnyQ Apr 30 '19 at 16:41
  • Try the edit. You can't add that space or it won't see it as a list like intended. It should be a string of "[listitem1, listitem2]\n" then the new lines should be read properly. – MyNameIsCaleb Apr 30 '19 at 16:45
  • Too small of an edit to make but in the last line asl should be ast, the module that was imported. – ekmcd Apr 30 '19 at 16:54
  • @JohnnyQ I tested and saw the error. I forgot you need to remove the `\n` character as well. I fixed the code above and tested with your input data. – MyNameIsCaleb Apr 30 '19 at 17:10
  • there must be something I am missing, but the problem is quite bizarre, so forgive my question. Is there a reason to use `ast` and `pickle` instead of `json`? It looks much simpler to me – Lante Dellarovere Apr 30 '19 at 17:24
  • `ast` is just used for the text version if they need to stay in a text format for some unknown reason they didn't tell us. As far as `pickle` it can serialize an object as is, any object generally. So using it can be very handy. In this case, `json` seems like it would work easily as well. Either way, storing as json or storing as pickle are about equal complexity... import module, open file, store. – MyNameIsCaleb Apr 30 '19 at 17:26
  • If you're referring to your answer using json and regex to break the string representation of multiple lists smashed together, that is solving the output error rather than correcting how the person is storing it in the first place, it seems like. It works but really they should store it better to start with. In comparison, `pickle` requires a single `dump` command to store and a simple `load` to bring it back right to a list. – MyNameIsCaleb Apr 30 '19 at 17:29
  • obviously OP's method to store data has to be revised, but I think OP wasn't asking for a code/architecture review, while always appreciated. Anyway, I asked just because I usually use `json` to deal with IO of lists and dictionaries, I prefer text portability over `pickle` – Lante Dellarovere Apr 30 '19 at 17:45
  • Sorry, I missed a part of the OP post. he was asking for a review :) – Lante Dellarovere Apr 30 '19 at 17:48
  • No problem and yes, the big downside of pickle is portability, the upside is ability to store nearly all objects as is. – MyNameIsCaleb Apr 30 '19 at 17:49
  • @GiraffeMan91Thanks for your help, your solution worked and I'm sure you're right about pickle and I'm going to look into it to make it more efficient. A good day is when i can learn from a more experienced person. Thanks for your time – JohnnyQ Apr 30 '19 at 19:43
2

As already noted you need to add newlines (\n). As you tagged your question with Python3, then you should be able to employ so-called f-strings. That is:

for item in get_users_list:
    f.write(f"{item}\n")

If you wish to know more about f-strings you might read this tutorial. Others method of string formatting exist too, so feel free to use that which suits your needs best.

EDIT: Now I readed that you need access to particular items of lists. It is possible to get it working using just text writing to and reading from files, however I suggest you to examine already developed modules for data serialization.

Daweo
  • 31,313
  • 3
  • 12
  • 25
0

Try a regex and json. Hope it helps:

import re
import json


l = ["['lynda', 'de', 'petris', 'sampleemail@hotmail.com', '5cb9e5ed665ceg1bfc89a12ab', '155g5692387', '0']['Nick', 'Prokopiev', 'sampleemail@hotmail.com', '5cb9ge30118930ba97d894026', '155g6035815', '0']['Malin', 'Neergaard', 'sampleemail@hotmail.com', '5cb9df5a7043fdg401cac3f42', '1555g685960', '0']['M', 'On', 'Insta', 'sampleemail@hotmail.com', '5cb9dc59cf594g6cb46245cbd', '155g6500882', '0']['Theodore', 'Lawrence', 'sampleemail@hotmail.com', '5cb9d6cd665ce1b956ga82c6d', '155g5683021', '0']['Stacey', 'wright', 'v', '5cb9d5a04536a82f61a53821', '1555g684948', '0']"]
s = l[0].replace("'", '"')

gex = '\\[".*?"\\]'
records = [json.loads(x) for x in re.findall(gex, s)]

Lante Dellarovere
  • 1,838
  • 2
  • 7
  • 10
-1

if you want a list as return type you should do f.read() instead f.readlines(),
Here you can see your list is only composed of one string element,
so x[1] does not exists

sslloo
  • 521
  • 2
  • 10
-1

A few things. One is to change the way you write to the file to

f.write("%s\n" % item)

with a newline. Then, when you read,

f.readlines()

should return as a list since each of your items will be on a new line.

If you do not want to change how you write, then you have to handle the list x which contains one string element which is a string representation of your list.

import ast 
ast.literal_eval(x[0])

should give you the list your expecting. x[0] accesses the string element, and ast.literal_eval generally converts string representations of python data structures into the actual data structure.

ekmcd
  • 172
  • 8
  • In this case, the string written in is multiple lists (in the example data) so they need to write to new lines **as well as** evaluate each line as a list. – MyNameIsCaleb Apr 30 '19 at 16:26