5

I am a beginner python user. Having trouble getting data from csv into python in the required object format to satisfy a python function. If I manually created the data in python (rather than bringing it in from csv) the following code works:

class Student(object):
   pass

john = Student()
#score tuple
john.score = (85.0, 42.0/2.0)

bob = Student()
bob.score = (45.0, 19.0/2.0)

john.rank = 1
bob.rank = 2

ExternalCode.AdjustStudents([john, bob])

However I need it to work automatically and not have to manually type out the data each time as there are going to be thousands of updates - hence the need to be able to bring in the data from csv.

The csv file format is: john, 85, 21, 1 bob, 45, 9.5, 2

Student objects would have a score attribute (columns 2 and 3 as a tuple) as well as a rank attribute (column 4). The required object format would be the same as produced by the manual code above.

An example of the required format produced by the manual code, is that when I do the following print after the manual code:

print(" John: score1={0[0]:.3f} score2={0[1]:.3f}".format(john.skill)) 

I get this result:

John: score1=25.000 score2=8.333

Cheers,

Steve

user8891420
  • 53
  • 1
  • 5
  • 1
    What is "the required object format"? Consider adding brief example CSV data, and show how you'd like the data to be represented when imported. – andrew_reece Nov 06 '17 at 00:59
  • The csv file format would be as follows: – user8891420 Nov 06 '17 at 01:41
  • Add a shortened version of your csv file and the desired output to the question. – skrx Nov 06 '17 at 01:48
  • john, 85, 21, 1 then bob would be the same format on the next line. All Student objects would have a score attribute (columns 2 and 3 as a tuple) as well as a rank attribute (column 4). The required format would be the same as produced by the manual code above. – user8891420 Nov 06 '17 at 01:53
  • ^ I suggest adding this data to your post. – andrew_reece Nov 06 '17 at 01:55

2 Answers2

2

If I understand you correctly, you're asking how you can create variables dynamically. Manipulating the globals() dict to create new variables is not a good idea and you should rather use a list or dictionary to store your csv data.

You seem to need a list, so:

  1. Define the list (student_list in the example below).
  2. Open the csv file.
  3. Create a csv.reader.
  4. Iterate over the rows.
  5. Convert the numbers to floats.
  6. Create a Student instance and pass the name and numbers.
  7. Finally append this student instance to the student_list.

So if your csv file looks like that,

name,score1,score2,rank
john,85,21,1
sarah,72,19,2
bob,45,19,3

try the following code:

import csv


class Student:

    def __init__(self, name, score, rank):
        self.name = name
        self.score = score
        self.rank = rank


student_list = []

with open('temp.csv', newline='') as csv_file:
    reader = csv.reader(csv_file)
    next(reader, None)  # Skip the header.
    # Unpack the row directly in the head of the for loop.
    for name, score1, score2, rank in reader:
        # Convert the numbers to floats.
        score1 = float(score1)
        score2 = float(score2)
        rank = float(rank)
        # Now create the Student instance and append it to the list.
        student_list.append(Student(name, (score1, score2), rank))

# Then do something with the student_list.
skrx
  • 18,183
  • 3
  • 28
  • 43
  • Thanks skrx. Seems to be getting close. However when I do the following print after the manual code: print(" John: score1={0[0]:.3f} score2={0[1]:.3f}".format(john.skill)) I get the following result: John: score1=25.000 score2=8.333 While if I do the same print code after the csv code from above I get: NameError: name 'john' is not defined. So it doesn't seem to be quite creating the same output. – user8891420 Nov 06 '17 at 10:04
  • There's no `john` variable anymore, because all the student instances are in the list now. If you want to access the students by name, you should rather put them into a [dictionary](https://www.python-course.eu/python3_dictionaries.php) instead of a list and access them in this way: `student_dict['john']`. The `Student` class would actually be unnecessary in this case. – skrx Nov 06 '17 at 15:37
  • Thanks skrx. The main aim of the code is to get the function call that works with the manual data i.e. ExternalCode.AdjustStudents([john, bob]) working with the dynamic code/data. If I put that function call down the bottom of your code and put in student_list instead of [john, bob] it doesn’t appear to work. How would you get that function call to work? – user8891420 Nov 08 '17 at 21:59
  • Do you get any error messages? If yes, post the full traceback. Also, how does the `ExternalCode.AdjustStudents` method work? What arguments does it take? If it worked with a list of your variables (which are `Student` instances), then it should work with the `student_list` as well. – skrx Nov 08 '17 at 22:15
  • In the manual code above I made the function call with ExternalCode.AdjustStudents([john, bob]). While with your dynamic code I used ExternalCode.AdjustStudents([student_list]). The error message I got is as follows: – user8891420 Nov 09 '17 at 10:55
  • Traceback (most recent call last): File "C:\Users\Steve\AppData\Local\Programs\Python\Python36-32\DynamicCode.py", line 100, in ExternalCode.AdjustStudents([student_list]) File "C:\Users\Steve\AppData\Local\Programs\Python\Python36-32\ExternalCode.py", line 328, in AdjustStudents students.sort(key=lambda p: p.rank) File "C:\Users\Steve\AppData\Local\Programs\Python\Python36-32\ExternalCode.py", line 328, in students.sort(key=lambda p: p.rank) AttributeError: 'list' object has no attribute 'rank' – user8891420 Nov 09 '17 at 10:55
  • The top chunk of the AdjustStudents function is as follows (it's a very long function, I think this part should give the most info on the error): def AdjustStudents(students): students = students[:] students.sort(key=lambda p: p.rank) ss = [Variable() for p in students] ps = [Variable() for p in students] ts = [Variable() for p in students] ds = [Variable() for p in students[:-1]] score = [PriorFactor(s, Gaussian(mu=pl.score[0], sigma=sqrt(pl.score[1] ** 2 + GAMMA ** 2))) for (s, pl) in zip(ss, students)] – user8891420 Nov 09 '17 at 11:03
  • The mistake is that you put `student_list` which is already a list into another list `[student_list]`. Just call `ExternalCode.AdjustStudents(student_list)`. – skrx Nov 09 '17 at 18:15
  • 1
    Thanks for your help skrx, that worked like a charm now! – user8891420 Nov 10 '17 at 11:12
0

You can read csv file with the help of pandas.

In pandas, there is read_csv("filename/filepath") function that reads data from csv file and store it as an array.

kimkevin
  • 2,142
  • 24
  • 48
  • Hi kimkevin, I did try pandas prior to posting. I could import the data into python fine, however still had difficulty getting the data in the required object format described above. – user8891420 Nov 06 '17 at 10:10