**Start with a solid foundation**. Even simple scripts like this can benefit by following a simple rule: put all algorithmic code inside of functions. At the top level, you can perform imports or define constants, functions, or classes. Everything else must be in functions. For this program, we could start with the following sketch: jack = {...} james = {...} dylan = {...} jess = {...} tom = {...} def main(): student = get_student() score = compute_score(student) letter = compute_grade(score) print(score, letter) def get_student(): return jack def compute_score(student): return 100 def compute_grade(score): return 'A' if __name__ == '__main__': main() **Take advantage of data structures**. You have 5 constants in the form of student dicts. And you have a name that will be entered by the program user (e.g., 'jack'). You don't need exotic techniques like `eval()` to transform that user-entered string into a Python variable. Rather, you need a dict mapping each student name to its corresponding dict of information about the student. This simple function will do the trick: def collect_students(): return { d['name'].lower() : d for d in (jack, james, dylan, jess, tom) } **Validate user input**. Once we have that utility function, we can implement the behavior to get user input and return the corresponding student dict. Code to collect user input should normally be written with an awareness that people make mistakes. A `while True` loop is often the most flexible mechanism for these situations: get the input, validate it, and return if OK: def get_student(): students = collect_students() while True: name = input('Enter student name: ') try: return students[name.lower()] except KeyError: pass **Use data structures to simplify algorithms**. Your code to compute the student's overall score is repetitive (it computes 3 different means) and hard to read (a long, dense line of code). However, if we define a simple data structure -- in this case, a dict mapping each type of coursework to its weight in the overall score -- we can compute the overall score more understandably: def compute_score(student): weights = {'assignment': 0.1, 'test': 0.7, 'lab': 0.2} return sum( w * mean(student[k]) for k, w in weights.items() ) def mean(vals): # Better: raise exception if vals is empty. # Even better: use statistics.mean(). return sum(vals) / len(vals) **Use data structures to simplify algorithms -- yet again**. Your code to compute the letter grade is algorithmically complex (relying on recursion) and opaque (with cryptic variable names like `asci` and `a`). None of that is needed if you define a dict mapping each minimum-score to its corresponding letter grade. (Note that this relies on the insertion-ordering property of dicts in modern Python.) def compute_grade(score): grades = {90: 'A', 80: 'B', 70: 'C', 60: 'D'} for min_score, letter in grades.items(): if score >= min_score: return letter return 'E'