Python for beginners
February 19, 2011 5:34 AM   Subscribe

Python noob alert... Looking to write a mood tracking program in python. I am definitely a noob programmer. I had one required class in college (mumble years ago). I know what I want to do, but I'm wondering if there's a more elegant way to do it.

So there will be about 20 prompts that I will rate from 0 to 4. I know I can have a variable for each question and then to get my score just do Q1+Q2...+Q20. (Like here)

But there's gotta be a more elegant way, right? Or am I better off sticking with the simple and worry about elegant down the road. I'm more interested in learning, but this is a serious project for me. Currently I'm using MoodScope (online) but it's lacking in some areas and thus doesn't give an accurate representation of my mood. Writing my own prompts will help me dial in on my specific issues.

As a side issue, right now I'm planning on presenting the prompts in 2 sets. One that's positively scored (happy, proud) and one that's reversed scored (sad, tearful, where 0=4, 1=3, etc). This is because I can't think of a good way to reverse score on the fly. Ideally I'd like the present the prompts randomly (which I've already figured out), but I can't do that if I can't reverse score right then and there.

I hope I've articulated the problems I'm having. As I said, I'm willing to learn. I've tried to Google, but I'm obviously not hitting on the right terms.

Please be gentle and use little words. FWIW, I'm using IDLE when I'm on my Win netbook and Emacs when I'm on my Linux desktop. Most of my time is spent on my desktop, but I do have an hour at work every afternoon where I play around with this.
posted by kathrynm to Computers & Internet (21 answers total) 3 users marked this as a favorite
Or am I better off sticking with the simple and worry about elegant down the road.

This is something that got in my way for a long time (and still gets in my way). You have an idea, so focus on the idea and get it working. Worry about elegance later. As a n00b, it's all too easy to get caught up in form over function.
posted by Cat Pie Hurts at 5:39 AM on February 19, 2011

I know I can have a variable for each question and then to get my score just do Q1+Q2...+Q20.

Unless you have a reason to store the results of each prompt, you might instead keep one variable ("mood"), and add or subtract the results of each of the 20 prompts to that variable. You can use the += and -= operators to increase or decrease a variable a set amount.
posted by Blazecock Pileon at 5:48 AM on February 19, 2011

I would do what Blazecock Pileon said as long as it's not important to store the individual variables but just the total mood.

Also, (4-input) will reverse the number, so...
for i in range(20):
 if (random.random() > 0.5):
  # happy question;
  input = repr(happyQuestion[i]);
  mood += input;
  # sad question
  input = repr(sadQuestion[i]);
  mood += (4-input);

posted by anaelith at 6:06 AM on February 19, 2011

Keep both the prompts and the answers in a list.
prompts = ["How's your mother?",
           "How're you feeling?",
           "How does your breath smell?"]

answers = [] #empty list, we'll fill it in later.

for p in prompts:
    ans = raw_input(p)
So, that's the basic idea. However, you have this pesky thing where you want one of the questions reversed. Honestly, for me, I wouldn't do that. I would find a way to reverse the answer.

But! If you can't do that for some reason, here's an option:
prompts = [("How's your mother?", false),
                  ("How horny are you?", false),
                  ("Rate how awesome Netzapper is.", true)]
answers = []

for p in prompts:
    ans = raw_input(p[0]) #that's the actual prompt
    ans = int(ans)
    if p[1]: #are we reversed?
        ans = 4 - ans;

posted by Netzapper at 6:11 AM on February 19, 2011 [1 favorite]

If you need to keep a record of the score for each question then use an array. For example use "response" as the name of the variable and then store the answer to the first question in response[1], the second in response[2] and so on.

Summing them is a case of iterating through the responses and you can easily add more questions in the future.
posted by mr_silver at 6:12 AM on February 19, 2011

Sorry, it should be

input = int(repr(happyQuestion[i]));


input = int(repr(sadQuestion[i]));

...&!#($ weakly typed languages........
posted by anaelith at 6:12 AM on February 19, 2011

Oh! To get your final score, you just iterate over answers.
mood_accumulator = 0
for a in answers:
    mood_accumulator += a
Or, if you wanted to show off what a total python badass you are:
mood_score = reduce(lambda sum, n: sum + n, answers)

posted by Netzapper at 6:23 AM on February 19, 2011 [1 favorite]

mood_score = reduce(lambda sum, n: sum + n, answers)

Or, if you were playing elegance golf, you could use

mood_score = sum(answers)

But as Cat Pie Hurts says, playing elegance golf can be detrimental to your productivity.
posted by Monday, stony Monday at 7:00 AM on February 19, 2011 [1 favorite]

I would worry about elegance and lambdas after you learn the basics of Python.
posted by Blazecock Pileon at 7:06 AM on February 19, 2011 [1 favorite]

true and false won't work in Python, they have to be capitalized: True and False. Another option is to have two lists of questions and first randomly choose the list then randomly choose a question from the list. Pseudocode:
from random import choice
mood = 0
# sad list, happy list
questions = [['my question 1', 'my question 2'], ['my question 3', ..]]
lsti = choice((0,1))  # later reverse score based on lsti
lst = questions[lsti]
question = choice(lst)
# ..
mood += int(ans) if lsti else 4-int(ans)
Don't worry about reduce and lambdas.. many python programmers don't use them; I've programmed in python for over a decade and never needed reduce and only used lambda a few times.
posted by rainy at 9:33 AM on February 19, 2011

Doh, with the code above, you have to pop the question from the list and also check if list is empty, something like:
from random import choice, randint
if lst:
  i = randint(0, len(lst))
  question = lst.pop(i)

posted by rainy at 9:38 AM on February 19, 2011

If you want more interactive help with this sort of thing, some of hang over in in ##python-friendly . You can try #python too if you are brave :) I am not brave. StackOverflow is also great when you have specific questions.

Focus on the "always working" mentality. Elegance comes later. Your app is *so small* that performance won't be an issue unless you do something really egregiously wrong :)

Best of luck!

posted by gregglind at 11:00 AM on February 19, 2011

Will your program save the data to a file? If so, I suggest that you record the answers to each question separately instead of adding them up and recording the total mood. You may only be interested in the total now, but you might be able to do some interesting analysis of the individual answers down the road.
posted by scose at 11:51 AM on February 19, 2011

My suggestion: start small, one step at a time. For example:
1. write a program to ask a single question, store the numerical value (no error checking) and print back the answer.
2. Do the same for two questions, adding the total score.
3. Do the same for a potentially arbitrary number of questions.
4. Add randomness in question order
5. Introduce two question categories.
6. Add error checking, so that the question is asked again if the user does not enter an accepted value.
7. save answers to a file, with the date included - ideally, appending to an existing file, so that you can go back in history, as suggested by scose above.
etc. At some point, you might even want to have a graphical user interface instead of working from a terminal!

You have to decide if you are going to use Python 2.x or Python 3.x. If you use Python 2.x, then to ask a question, one uses raw_input. For Python 3.x, raw_input has been renamed input. In Python 2.x, input is a different built-in function. Do NOT use the example(s) given by anaelith above, as (s)he write "input" as a user-defined variable, and also over-complicate things needlessly.

If you use Python 2.x, then you'd have something like

answer = int( raw_input("Question for which you want an answer between 0 and 4 " ))

If you use Netzapper's approach, to get the total score at the end, you simply do
total_score = sum(answers)

Feel free to memail me if you have any specific question.

Good luck!
posted by aroberge at 2:59 PM on February 19, 2011

Oh wow. What an amazing set of answers. I have a lot to digest.

In response, I'm using Python 2.5.2 on my desktop. I'm not sure about my laptop, but I'm sure it's some flavor of 2.x.

I am taking this in small steps. This happens to be the step I'm on. I do have my prompts in a list (or was it a tuple, I'm not quite sure I grasp the differences between them.

Eventually when I get this working, I want to send the total score to a file (cvs?) so I can import into a spread sheet to make graphs (though I'm sure Python has a module to do that too).

Scose has a really good point. I may want to look at physical vs. emotional "symptoms" in the future. So maybe the quick and dirty method I was first thinking of isn't such a silly idea.

aroberge, I might take you up on your offer to go to memail. Let me see what I can do on my own. As much as I'd love to get on this *right now*, I have a half dozen tests to write today. Anyone want to write some ESL tests?? :-)
posted by kathrynm at 3:30 PM on February 19, 2011

As a general rule of thumb of programming, if at any point you ever find yourself labeling more than a couple of variables with sequential names like "foo1", "foo2", "foo3", ... or you ever find that you're listing things out by hand like "foo1 + foo2 + foo3 + ..." then you are doing it wrong and you should stop and look for a language feature that does what you want. All programming languages provide a better way of handling this, whether they call them lists, hashes, arrays, vectors, tuples, or whatever.
posted by Rhomboid at 5:04 PM on February 19, 2011

There's an important difference between tuples and lists: lists can be modified (in python-speak, they're 'mutable'), tuples can not.

lst = [1,2,3]
lst[1] = 4
tup = (1,2,3)
tup[1] = 4
TypeError exception

Lists have all kinds of methods for modifying its contents, they can be sorted, etc.

Tuples are lighter structures to be used when you don't need to modify them.

By the way, you should probably use python 2.7, as some code you find online may not work in 2.5, and 2.7 is just generally nicer. For example some of the code i used in my replies above probably doesn't work in 2.5 (e.g. x=1 if y else 2 may or may not work, I don't remember).
posted by rainy at 5:09 PM on February 19, 2011

Thanks rainy. Just another reason to get off my lazy butt and upgrade my desktop. Fedora isn't playing nice with my hardware anymore and I know aptosid does. I've just been too lazy to actually do it. And a bit afraid to jump into the Debian way after 3 years of the RH way.
posted by kathrynm at 12:54 AM on February 20, 2011

Rhomboid... That is the exact reason for my question. I know there had to be a better way, I just didn't know how to search for it.

I'm in awe of the smart people here. I'm so glad I joined.
posted by kathrynm at 12:55 AM on February 20, 2011

Oh, for "looking for better ways", I found the Python Quickref useful; it's a bit overwhelming (50 densely packed pages), but you often go "ooooh, that's how".
posted by Monday, stony Monday at 6:28 AM on February 20, 2011

Oh that's nice Monday, stony Monday. I'll print it out at work today.
posted by kathrynm at 4:07 PM on February 20, 2011

« Older Austin Here We Come   |   My former employer leaked my ss number! Newer »
This thread is closed to new comments.