13

Even though initializing variables in python is not necessary, my professor still wants us to do it for practice. I wrote my program and it worked fine, but after I tried to initialize some of the variables I got an error message when I tried to run it. Here is the first part of my program:

def main():

    grade_1, grade_2, grade_3, average = 0.0
    year = 0

    fName, lName, ID, converted_ID = ""
    infile = open("studentinfo.txt", "r")
    data = infile.read()
    fName, lName, ID, year = data.split(",")
    year = int(year)

    # Prompt the user for three test scores

    grades = eval(input("Enter the three test scores separated by a comma: "))

    # Create a username

    uName = (lName[:4] + fName[:2] + str(year)).lower()
    converted_id = ID[:3] + "-" + ID[3:5] + "-" + ID[5:]
    grade_1, grade_2, grade_3 = grades

The error message:

grade_1, grade_2, grade_3, average = 0.0

TypeError: 'float' object is not iterable
6
  • 1
    grade_1, grade_2, grade_3, average = 0.0, 0.0, 0.0, 0.0
    – sobolevn
    Commented Jun 16, 2015 at 3:46
  • 1
    grade_1 = grade_2 = grade_3 = average = 0.0 Commented Jun 16, 2015 at 3:49
  • 7
    I'm sorry, but "practice" for what? What other unnecessary things are you practicing in that class? Commented Jun 16, 2015 at 3:56
  • 1
    @TigerhawkT3 Haha it's practice for when (if) we take classes on other languages
    – Ovi
    Commented Jun 16, 2015 at 4:03
  • 3
    I would expect the Python class to cover Python, with strategies for other languages being covered in their respective classes... =\ Commented Jun 16, 2015 at 5:08

7 Answers 7

23

There are several ways to assign the equal variables.

The easiest one:

grade_1 = grade_2 = grade_3 = average = 0.0

With unpacking:

grade_1, grade_2, grade_3, average = 0.0, 0.0, 0.0, 0.0

With list comprehension and unpacking:

>>> grade_1, grade_2, grade_3, average = [0.0 for _ in range(4)]
>>> print(grade_1, grade_2, grade_3, average)
0.0 0.0 0.0 0.0
0
20

I know you have already accepted another answer, but I think the broader issue needs to addressed - programming style that is suitable to the current language.

Yes, 'initialization' isn't needed in Python, but what you are doing isn't initialization. It is just an incomplete and erroneous imitation of initialization as practiced in other languages. The important thing about initialization in static typed languages is that you specify the nature of the variables.

In Python, as in other languages, you do need to give variables values before you use them. But giving them values at the start of the function isn't important, and even wrong if the values you give have nothing to do with values they receive later. That isn't 'initialization', it's 'reuse'.

I'll make some notes and corrections to your code:

def main():
   # doc to define the function
   # proper Python indentation
   # document significant variables, especially inputs and outputs
   # grade_1, grade_2, grade_3, average - id these
   # year - id this
   # fName, lName, ID, converted_ID 

   infile = open("studentinfo.txt", "r") 
   # you didn't 'intialize' this variable

   data = infile.read()  
   # nor this  

   fName, lName, ID, year = data.split(",")
   # this will produce an error if the file does not have the right number of strings
   # 'year' is now a string, even though you 'initialized' it as 0

   year = int(year)
   # now 'year' is an integer
   # a language that requires initialization would have raised an error
   # over this switch in type of this variable.

   # Prompt the user for three test scores
   grades = eval(input("Enter the three test scores separated by a comma: "))
   # 'eval' ouch!
   # you could have handled the input just like you did the file input.

   grade_1, grade_2, grade_3 = grades   
   # this would work only if the user gave you an 'iterable' with 3 values
   # eval() doesn't ensure that it is an iterable
   # and it does not ensure that the values are numbers. 
   # What would happen with this user input: "'one','two','three',4"?

   # Create a username 
   uName = (lName[:4] + fName[:2] + str(year)).lower()

   converted_id = ID[:3] + "-" + ID[3:5] + "-" + ID[5:]
   # earlier you 'initialized' converted_ID
   # initialization in a static typed language would have caught this typo
   # pseudo-initialization in Python does not catch typos
   ....
2
  • are you the teacher ?? :) nice explanations to different aspects. Commented Jun 16, 2015 at 10:28
  • I'm glad this answer exists. In Python variables hold references to objects so you don't exactly allocate memory for it. There is no need to initiliase a variable to avoid any junk residing in memory. And since it is dynamically-typed, a variable can hold an integer at one moment, a string at another and a list of integers, floats, strings and functions (all at the same) at yet another moment. So just give a value to your variable the first time you'll need it and think nothing more of it.Important quote, That isn't 'initialization', it's 'reuse'.
    – Reti43
    Commented Dec 16, 2015 at 13:56
14

The issue is in the line -

grade_1, grade_2, grade_3, average = 0.0

and

fName, lName, ID, converted_ID = ""

In python, if the left hand side of the assignment operator has multiple variables, python would try to iterate the right hand side that many times and assign each iterated value to each variable sequentially. The variables grade_1, grade_2, grade_3, average need three 0.0 values to assign to each variable.

You may need something like -

grade_1, grade_2, grade_3, average = [0.0 for _ in range(4)]
fName, lName, ID, converted_ID = ["" for _ in range(4)]
1
  • list comprehension [0.0 for _ in range(4)] might be replaced with shallow copy of the object: [0.0] * 4. Note: it is shallow copy, so be careful when using mutable objects, e.g. [[]] * 4 is probably not what you wanted as it creates 4 elements pointing to the same empty list.
    – ROJI
    Commented Jul 27, 2020 at 16:47
5

Python treats comma on the left hand side of equal sign ( = ) as an input splitter, Very useful for functions that return a tuple.

e.g,

x,y = (5,2)

What you want to do is:

grade_1 = grade_2 = grade_3 = average = 0.0

though that might not be the most clear way to write it.

3

You are asking to initialize four variables using a single float object, which of course is not iterable. You can do -

  1. grade_1, grade_2, grade_3, grade_4 = [0.0 for _ in range(4)]
  2. grade_1 = grade_2 = grade_3 = grade_4 = 0.0

Unless you want to initialize them with different values of course.

2
  • You do not need range(0,4) , when you give range(4) , it automatically starts at 0 . Also, preferable to use xrange in python 2.x for better memory usage. Commented Jun 16, 2015 at 4:03
  • I have made the change, it's ok now??
    – hspandher
    Commented Jun 16, 2015 at 4:05
2

If you want to use the destructuring assignment, you'll need the same number of floats as you have variables:

grade_1, grade_2, grade_3, average = 0.0, 0.0, 0.0, 0.0
0
def grade(inlist):
    grade_1, grade_2, grade_3, average =inlist
    print (grade_1)
    print (grade_2)

mark=[1,2,3,4]
grade(mark)

Not the answer you're looking for? Browse other questions tagged or ask your own question.