0

I'm quite new to python, and as a little project, I am trying to make an interactive program where I can store recipes, each recipe will be stored as a list of the format: [Name, Servings, [List of ingredients], [List of steps in method]]

The first function, that creates the list works (i.e. I have created and stored in the file [Scrambled eggs, 1, [2 eggs, milk.....], [Beat the eggs....]]

However when I then call the 'view_recipes' function, I get:

Name:  [
Servings:  '
Ingredients:
S
Method:
c

so it is clearly iterating over characters in the string.

Is it a problem with how I write my list to my file? (I've looked this up before and everyone says you just need to have f.write(str(list)) Else it must be a problem with the reading of a file: but how can I get python to import it as a list of lists?

My code so far:

import re
#Input file
f = open("bank.txt", "r+")

def add_recipe():
    recipe = []
    ingredients = []
    method = []
    #recipe = [name, servings, ingredients(as list), method(as list)]
    recipe.append(raw_input("Please enter a name for the dish: "))
    recipe.append(raw_input("How many servings does this recipe make? "))
    print "Ingredients"
    ans = True
    while ans:
        i = raw_input("Enter amount and ingredient name i.e. '250g Flour' or 'x' to continue: ")
        if i.lower() == "x":
            ans = False
        else:
            ans = False
            ingredients.append(i)
            ans = True
    print "Ingredients entered: "
    for ing in ingredients:
        print ing
    recipe.append(ingredients)
    print "Method: "
    ans2 = True
    while ans2:
        j = raw_input("Type next step or 'x' to end: ")
        if j.lower() == "x":
            ans2 = False
        else:
            ans2 = False
            method.append(j)
            ans2 = True
    print "Method: "
    for step in method:
        print step
    recipe.append(method)
    print "Writing recipe information to file..."
    print recipe
    f.write(str(recipe))
    f.write("\n")

def view_recipes():
    for line in f:
        print "Name: ", list(line)[0]
        print "Servings: ", list(line)[1]
        print "Ingredients: "
        for k in list(line)[2]:
            print k
        print "Method: "
        for l in list(line)[3]:
            print l
fredtantini
  • 15,966
  • 8
  • 49
  • 55
ACrazyChemist
  • 55
  • 1
  • 9
  • If you have the representation of a list stored in the file (e.g. `"['eggs', 'milk']"`), you will need [`ast.literal_eval`](https://docs.python.org/2/library/ast.html#ast.literal_eval) to get the object back. Alternatively, consider a proper [CSV](https://docs.python.org/2/library/csv.html) format – jonrsharpe Aug 19 '14 at 11:23
  • If you are not interested in a particular format of the file, only in being able to get your data back, then the [pickle module](https://docs.python.org/3/library/pickle.html) is what you are looking for. It can serialize an arbitrary Python object (even if it involves objects of custom classes etc.) and reconstruct it exactly. It uses a custom format, even using compression. It works correctly even if several references to the same object exist in the data structure and will not create multiple separate copies of that object upon reconstruction. – Lutz Prechelt Feb 27 '15 at 13:11

1 Answers1

0

I think your problem is that list(line) transform a string into a list of characters:

>>> l = "abc"
>>> list(l)
['a', 'b', 'c']

You should use something like pickle to read/write data to a file.

See for example this answer.

Edit: In order to be able to add more recipes to your file, you can

  • add all your recipes to some variable and read/write all at once

For instance something like

recipes = []
want_to_add_recipe = True
while want_to_add_recipe:
    recipes.append(add_recipe())
    ans = raw_input('more? ')
    want_to_add_recipe = True if ans == 'y' else False
with open("Recipe.txt", "wb") as fo:
    pickle.dump(recipe, fo)

And in add_recipe:

with open("Recipe.txt", "rb") as fo:
    recipes = pickle.load(fo)
for name, serving, ingredients, method in recipes:
    #print things        

You will have to change add_recipe to return recipe.

  • add recipe to your file each time you call add_recipe:
    • read your file
    • load recipes if they exist
    • add your recipe to recipes
    • write the new recipes to the file

Also, check @jonrsharpe comment. You could easily use sqlite3 to avoid drawbacks of both my methods.

Community
  • 1
  • 1
fredtantini
  • 15,966
  • 8
  • 49
  • 55
  • This seems like a good method, however when I put in two recipes, it just overwrites the file. Using "a+" as mode when performing with open("bank.txt", "a+") as fo: pickle.dump((name, servings, ingredients, method), fo) doesn't seem to have fixed it! – ACrazyChemist Aug 19 '14 at 11:34
  • @ACrazyChemist see http://stackoverflow.com/q/20716812/3001761 (especially Tim Peters' comment on not reinventing the database...) – jonrsharpe Aug 19 '14 at 11:36
  • @fredtantini Thanks for the update, however as far as I can tell, sqlite3 isn't particularly compatible with python lists as a datatype? it deals with int/float and txt types very well. If I decide to take this project further and, for example make a shopping list compiler, then I would need to be able to easily access specific items in the python list 'ingredients'. Regardless, SQL is still on my list of modules to have a look at. – ACrazyChemist Aug 19 '14 at 13:32