'Why is 'NoneType' object not iterable in HackerRank, but not PyCharm?

Using Python 3.x, I'm trying to round up students grades given a teacher's weird way of grading. Basically, if the student grade is below 38, do nothing. If the difference between the grade and the next multiple of 5 is less than 3, round the grade up to the next multiple of 5. Otherwise, don't change the grade. Here is the code I've used in both PyCharm and HackerRank's web-based IDE:

grades = [37, 39, 52, 83, 91]

def gradingStudents(grades):
    for i in range(len(grades)):
        grade = grades[i]
        if grade > 38:
            for j in range(4):
               next_val = grade + j
               if ((next_val-grade) < 3) and (next_val%5 == 0):
                   grade = next_val
        print(grade)

gradingStudents(grades)

The output in PyCharm is correct:

37
40
52
85
91

For comparison, here is the code from from the web-based IDE in HackerRank (https://www.hackerrank.com/):

#!/bin/python3
import os
import sys

#
# Complete the gradingStudents function below.
#
def gradingStudents(grades):
    for i in range(len(grades)):
        grade = grades[i]
        if grade > 38:
            for j in range(4):
               next_val = grade + j
               if ((next_val-grade) < 3) and (next_val%5 == 0):
                   grade = next_val
        print(grade)

if __name__ == '__main__':
    f = open(os.environ['OUTPUT_PATH'], 'w')

    n = int(input())

    grades = []

    for _ in range(n):
        grades_item = int(input())
        grades.append(grades_item)

    result = gradingStudents(grades)

    f.write('\n'.join(map(str, result))) #<-- This is line 32 from error!
    f.write('\n')

    f.close()

This throws the following error:

Traceback (most recent call last):
File "solution.py", line 32, in <module>
f.write('\n'.join(map(str, result)))
TypeError: 'NoneType' object is not iterable


Solution 1:[1]

Hackerrank is expecting a list of grades to be returned from your function, you are returning nothing, just printing.

def gradingStudents(grades):
    result = []  # make an empty list
    for i in range(len(grades)):  # assuming this logic is correct
        grade = grades[i]
        if grade > 38:
            for j in range(4):
                next_val = grade + j
                if ((next_val-grade) < 3) and (next_val%5 == 0):
                    grade = next_val

        result.append(grade)  # append the grade to list
    return result # return the list, you had no return statement so it was returning none

Solution 2:[2]

The problem is because your function returns nothing or None, and therefore join will return an error. print only prints the value and does not return anything, yes it prints in your PyCharm IDE but nothing is being returned from it.

If you want to use those values, I have slightly modified your code for it to return a new list after applying your logic by adding f_grades which is a list in the function.

import os
import sys

#
# Complete the gradingStudents function below.
#
def gradingStudents(grades):
    f_grade = []
    for i in range(len(grades)):
        grade = grades[i]
        if grade > 38:
            for j in range(4):
                next_val = grade + j
                if ((next_val-grade) < 3) and (next_val%5 == 0):
                        grade = next_val
                        f_grade.append(grade)
    return f_grade

if __name__ == '__main__':
    #f = open(os.environ['OUTPUT_PATH'], 'w')

    n = int(input())

    grades = []

    for _ in range(n):
        grades_item = int(input())
        grades.append(grades_item)

    result = gradingStudents(grades)

    f.write('\n'.join(map(str, result))) #<-- No more error!
    f.write('\n')

    f.close()

What it does instead, without rewriting the whole code, is that it adds those values in a new list after it passes the logic and returns that list. From there you will be able to apply functions to that list like join.

Solution 3:[3]

Here is a list-comprehension way of doing the same:

def gradingStudents(grades):
    return [5 * (x // 5) + 5 if x > 38 and x % 5 > 2 else x for x in grades]

print(gradingStudents([37, 39, 52, 83, 91]))
# [37, 40, 52, 85, 91]

This would be more efficient considering it's a comprehension and is also concise.

Solution 4:[4]

In hackerrank you have to return value(s) when the print command had the "The object is not iterable" issue.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vaibhav Vishal
Solution 2 BernardL
Solution 3 Austin
Solution 4 Jamal Azizbeigi