An00bis
An00bis

Reputation: 63

Error testing python code: TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

New to Python and am trying to answer a homework problem where: a hospital records how many patients they are dealing with, the required nutrition to be provided to each patient, and then averaging required nutrition per patient after summing the totals.

Now when I'm testing/validating data entry, I see my code is causing errors because of the clumsy way I've tried to solve the problem. When testing, I get this:

TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

I've tried going through and messing with the return functions, but if it's not there, I think the issue might be with my read_input() functions. I've been messing around with PythonTutor, so I can visualize where the error is...I just have no idea how to get out of this loop and fix it.

my code so far

def validate_positive_patients(n):

    try:
        n = float(n)
        if n <= 0:
            print("Please enter a nonnegative number")
            return n, False

    except ValueError:
        print("Please enter a positive integer")
        return None, False
    return n, True

def read_input(float):
    value, positive = validate_positive_patients(input(float))
    if not positive:
        read_input(float=float)
    else:
        return value

# rest of code seems to work fine

My code is clumsy, but what I'd really like it to do is only accept int values for 'number of patients', floats for protein, carbs etc., and if there is an entry error initially to not just spit out a None value.

If only computers knew what you wanted them to do instead of what I'm telling it to do :P Thanks in advance for any help!

Upvotes: 2

Views: 5230

Answers (2)

gmds
gmds

Reputation: 19885

By default, Python functions return None.

In your original code, in read_input, if the value entered is not positive, then you never hit a return statement, and accordingly return None.

I've cleaned up your code a little, while attempting to preserve its spirit:

def get_positive_int(message):
    while True:
        input_value = input(message)
        if input_value.isdigit() and int(input_value) > 0:
            return int(input_value)

        else:
            print('Please enter a positive number.')

def get_positive_float(message):
    while True:
        input_value = input(message)
        try:
            float_value = float(input_value)
            if float_value > 0:
                return float_value

        except ValueError:
            pass

        print('Please enter a positive real number.')

def calculate_average(nutrition, total_quantity, total_patients):
    average = total_quantity / total_patients
    print(f'{nutrition} {average}')

number_of_patients = get_positive_int("Enter number of patients: ")

protein, carbohydrates, fat, kilojoules = 0, 0, 0, 0

for i in range(int(number_of_patients)):
    print(f'Patient {i + 1}')
    protein += get_float("Amount of protein (g) required: ")
    carbohydrates += get_float("Amount of carbohydrates (g) required: ")
    fat += get_float("Amount of fat (g) required: ")
    kilojoules += 4.18*(4*protein + 4*carbohydrates + 9.30*fat)

print("Averages:")
calculate_average(nutrition = "Protein (g): ", total_quantity = protein,
                  total_patients = number_of_patients)
calculate_average(nutrition = "Carbohydrates (g): ", total_quantity = 
                  carbohydrates, total_patients = number_of_patients)
calculate_average(nutrition = "Fat (g): ", total_quantity = fat,
                  total_patients = number_of_patients)
calculate_average(nutrition = "Kilojoules (kJ): ", total_quantity =
                  kilojoules, total_patients = number_of_patients)

In particular, it is unwise to shadow builtins (using float as a parameter name), and f-strings can make your code easier to read.

Upvotes: 3

OneCricketeer
OneCricketeer

Reputation: 191728

You'd be getting None because you're ignoring a value when you call read_input again in the if statement.

The alternative would be to just loop, not call the same function

def read_input(prompt):
    positive = False
    while not positive:
        value, positive = validate_positive_patients(input(prompt))
    return value 

And I suggest you use while loops so that it continously checks the results

Note that you're also doing return None, False in the first function, so you still should check that value is not None before actually returning a numeric value

Also Check if input is positive integer

Upvotes: 1

Related Questions