Python Forum

Full Version: Pre-release practice help!
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Myself and a friend have been trying to do the pre-release of a previous year's iGCSE as practice. We tend to write short and simple code, rather than the 150+ line answers I've seen elsewhere. We fixed a few errors but there is one that we cannot fix, and neither can our teacher.

The code given is meant to ask you for how many sacks of each material you want, and then for how heavy each sack is. Then, using a self-made function the sacks are either accepted with their weight added to the total weight or rejected and put on to the rejected counter. Then at the end it prints the total weight of the accepted sacks and the number of sacks that were rejected.

The problem is that the total weight and rejected counter reset every time the code exits our function, resulting in it telling us that there is 0kg and 0 rejected sacks. Can anyone help without altering the code too dramatically? Thanks!

import sys
import time

#-------------------------------------------------------------------------------------------------------------------------------------------------------

def bag_check(material, weight, total_kg, rejected):
    valid_kg = False
    
    if material == "Sand" or material == "Gravel":
        if weight < 49.9:
            valid_kg = False
        elif weight > 50.1:
            valid_kg = False
        else:
            valid_kg = True
    elif material == "Cement":
        if weight < 24.9:
            valid_kg = False
        elif weight > 25.1:
            valid_kg = False
        else:
            valid_kg = True
    
    if valid_kg:
        total_kg += weight
    else:
        rejected += 1

#-------------------------------------------------------------------------------------------------------------------------------------------------------

total_kg = 0
rejected = 0


num_C = int(input("How many bags of cement are needed?"))
if num_C < 0:
    print("You cannot have a negative amount of sacks.")
    time.sleep(2)
    sys.exit()
num_G = int(input("How many bags of gravel are needed?"))
if num_G < 0:
    print("You cannot have a negative amount of sacks.")
    time.sleep(2)
    sys.exit()
num_S = int(input("How many bags of sand are needed?"))
if num_S < 0:
    print("You cannot have a negative amount of sacks.")
    time.sleep(2)
    sys.exit()


if num_C > 0:
    print("The following questions are for cement sacks:")
    for sacks in range(0,num_C):
        bag_check("Cement", float(input("How heavy is the sack in kg?")), total_kg, rejected)

if num_G > 0:
    print("The following questions are for gravel sacks:")
    for sacks in range(0,num_G):
        bag_check("Gravel", float(input("How heavy is the sack in kg?")), total_kg, rejected)

if num_S > 0:
    print("The following questions are for sand sacks:")
    for sacks in range(0,num_S):
        bag_check("Sand", float(input("How heavy is the sack in kg?")), total_kg, rejected)


print("The total weight of the accepted sacks in the order is", total_kg, "kg and there are", rejected, "rejected sacks.")
Output:
How many bags of cement are needed?2 How many bags of gravel are needed?3 How many bags of sand are needed?4 The following questions are for cement sacks: How heavy is the sack in kg?25 How heavy is the sack in kg?25 The following questions are for gravel sacks: How heavy is the sack in kg?50 How heavy is the sack in kg?50 How heavy is the sack in kg?46787 The following questions are for sand sacks: How heavy is the sack in kg?50 How heavy is the sack in kg?50 How heavy is the sack in kg?4679 How heavy is the sack in kg?50 The total weight of the accepted sacks in the order is 0 kg and there are 0 rejected sacks.
I think you need to declare your total_kg and rejected variables before the bag_check function, then use them globally, like this:
total_kg = 0
rejected = 0
def bag_check(material, weight, total_kg, rejected):
   global total_kg
   global rejected
   # the rest of the function
(Nov-05-2017, 12:41 PM)Lux Wrote: [ -> ]I think you need to declare your total_kg and rejected variables before the bag_check function, then use them globally, like this:
total_kg = 0
rejected = 0
def bag_check(material, weight, total_kg, rejected):
   global total_kg
   global rejected
   # the rest of the function

It didn't work, I get the error "name 'total_kg' is parameter and global"

(Nov-05-2017, 02:47 PM)Wilson1218 Wrote: [ -> ]
(Nov-05-2017, 12:41 PM)Lux Wrote: [ -> ]I think you need to declare your total_kg and rejected variables before the bag_check function, then use them globally, like this:
total_kg = 0
rejected = 0
def bag_check(material, weight, total_kg, rejected):
   global total_kg
   global rejected
   # the rest of the function

It didn't work, I get the error "name 'total_kg' is parameter and global"


Fixed it, simple parameter error. Thanks!
globals is not the way to go. it is discouraged to use globals. your function should return the result.
However it is better if your function return just True or False - if the bag is valid weight. Calculation should be outside it.

def number_bags(material):
    while True:
        try:
            num = int(input('How many bags of {} are needed?'.format(material)))
        except ValueError:
            continue
        if num > 0:
            return num
        else:
            print('You cannot have a negative amount of sacks.')


def bag_weight(bag_num):
    while True:
        try:
            weight = float(input('How heavy is the sack#{} in kg: '.format(bag)))
        except ValueError:
            continue
        if weight > 0:
            return weight
        else:
            print('You cannot have a negative weight of sacks.')


def check_bag(material, weight):
    valid_weights = {'sand':(49.9, 50.1),
                     'gravel':(49.9, 50.1),
                     'cement':(24.9, 25.1)}

    min_weight, max_weight = valid_weights[material]
    return min_weight <= weight <= max_weight
 

if __name__ == '__main__':
    materials = ['cement', 'gravel', 'sand']
    total = 0
    rejected = 0
    for material in materials:
        bags = number_bags(material)
        for bag in range(1, bags+1):
            weight = bag_weight(bag)
            if check_bag(material, weight):
                total += weight
            else:
                rejected += 1
    print('The total weight of the accepted sacks in the order is {:.1f}kg'.format(total))
    print('There are {} rejected sacks.'.format(rejected))