0

I'm trying to adapt an exercise that will spit out a student's grade, so that instead of putting the name in the code eg

print get_letter_grade (get_average(alice))

I want to use user input. I personally tend to automatically type names with a capital (ie Alice), so I needed to santise my inputs, using .lower() The code works without .lower as long as I don't use uppercase.

The errors seem to be for all lowercase input AttributeError: 'dict' object has no attribute 'lower'

And for upper case (ie Alice) input: NameError: name 'Tyler' is not defined:

 pupil = input("Which student?").lower()
    print get_letter_grade (get_average(
      pupil))

Tried:

pupil = input("Which student?").lower
    student = pupil
    print get_letter_grade (get_average(
      student))

Also tried:

pupil = input("Which student?")
student = pupil.lower()
print get_letter_grade (get_average(
  student))

And:

pupil = input("Which student?")
student = pupil
print get_letter_grade (get_average(input("Which student?").lower()))

Here's the full code:

lloyd = {
    "name": "Lloyd",
    "homework": [90.0, 97.0, 75.0, 92.0],
    "quizzes": [88.0, 40.0, 94.0],
    "tests": [75.0, 90.0]
    }
alice = {
    "name": "Alice",
    "homework": [100.0, 92.0, 98.0, 100.0],
    "quizzes": [82.0, 83.0, 91.0],
    "tests": [89.0, 97.0]
    }
tyler = {
    "name": "Tyler",
    "homework": [0.0, 87.0, 75.0, 22.0],
    "quizzes": [0.0, 75.0, 78.0],
    "tests": [100.0, 100.0]
    }

def average(numbers):
    total=sum(numbers)
    total=float(total)
    total =total/len(numbers)
    return total

def get_average(student):
    homework = average(student["homework"])
    quizzes = average(student["quizzes"])
    tests = average(student["tests"])
    return float(0.1*homework + 0.3*quizzes + 0.6*tests)

def get_letter_grade(score):
    if score>=90:
        return "A"
    elif score>=80:
        return "B"
    elif score>=70:
        return "C"
    elif score>=60:
        return "D"
    else:
        return "F"

pupil = input("Which student?").lower()

print get_letter_grade (get_average(
  pupil))

I feel like I'm misunderstanding things about how user input is used/processed, or something to do with formatting strings, dictionaries?

toonarmycaptain
  • 2,093
  • 2
  • 18
  • 29
  • If the input is ``alice`` all you get as ``student`` is really just the string ``"alice"`` - it will by no means suddenly turn into a reference to your global ``alice`` dictionary. Tip: start small. Instead of writing a full-blown program, start with identifying and referencing the correct dictionary based on a user's input. That way there are less potential errors to run into. – Mike Scotty May 03 '17 at 14:35

3 Answers3

4

In short - don't try to do it like this. You shouldn't be using user inputs to refer to variables as it's messy. You could instead use nested dictionaries. Try the following - I've removed your methods to keep this concise, but make sure you still include them:

all_pupils = {
    "Lloyd": {
        "homework": [90.0, 97.0, 75.0, 92.0],
        "quizzes": [88.0, 40.0, 94.0],
        "tests": [75.0, 90.0]
    },
    "Alice": {
        "homework": [100.0, 92.0, 98.0, 100.0],
        "quizzes": [82.0, 83.0, 91.0],
        "tests": [89.0, 97.0]
    },
    "Tyler": {
        "homework": [0.0, 87.0, 75.0, 22.0],
        "quizzes": [0.0, 75.0, 78.0],
        "tests": [100.0, 100.0]
    }
    }

# re-insert methods here...

pupil = raw_input("Which student?").title()

if pupil in all_pupils.keys():
    print get_letter_grade(get_average(all_pupils[pupil]))
else:
    print 'Student not found!'

Couple of changes here. Based on your print statements I assume you are using Python 2.x, in which case you should use raw_input() not input(). We convert this input using .title() to match the title case of our dictionary keys. Additionally, we add a check to see if the pupil exists in our dictionary (if pupil in all_pupils.keys():) and report an error message if the name cannot be found.

asongtoruin
  • 9,794
  • 3
  • 36
  • 47
1

As @mpf82 already said your user input is just a plain string and won't reference to your dictionary. What you could do is to add your dictionary to a collection and make a list comprehension to get the correct dictionary by the name.

pupils = [lloyd, alice, tyler]

student = next(x for x in pupils if x["name"].lower()==pupil)

For the second line see: find first sequence item that matches a criterion

this doesn't really look nice I think but it'll do the trick here.

Be aware, that in case that you have more students with the same name you will end up only getting the first occurence

Community
  • 1
  • 1
1
  • For dictionary access, you have to use the key exactly equal to the key in the dictionary. If you use a lowercase string like 'alice', your key should be exactly 'alice', not e.g. 'Alice'.

  • To access something by name, put it into a dict. You cannot (or, rather, should not) try to look up variables by name.

Here's a working example:

people = {
   'ada': {
      'name': 'Ada Lovelace',
      'role': 'Programmer',
   },
   'charles': {
      'name': 'Charles Babbage',
      'role': 'Hardware designer',
   },
}

moniker = raw_input('Who? ').lower()

if moniker in people:
  person = people[moniker]
  print person['name'], ',', person['role']
else:
  print 'No idea who is that.'
9000
  • 39,899
  • 9
  • 66
  • 104
  • I attempted to edit it such that: students= { 'lloyd': { "name": "Lloyd", "homework": [90.0, 97.0, 75.0, 92.0], "quizzes": [88.0, 40.0, 94.0], "tests": [75.0, 90.0] }, } pupil = raw_input("Which student?").lower if pupil in students: student = students[pupil] print get_letter_grade(get_average( student)) else: print "Unknown student." ---but now it shows "Unknown student." no matter what I enter :s – toonarmycaptain May 03 '17 at 16:32
  • my bad, forgot the brackets after lower() thankyou! – toonarmycaptain May 03 '17 at 16:51