Python Forum
Rounding exercise: UnboundLocalError: local variable referenced before assignment
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Rounding exercise: UnboundLocalError: local variable referenced before assignment
#1
This is for a personal challenge, not for school.

The task at hand:

Write a function which collects a list of floats as well as a boolean option. When the option is set to True, round up to the nearest full integer. However when the option is set to False, round down.

Here is my script that I came up with:
from math import ceil, floor

list_of_floats = [1.23, 4.32, 4.96, 16.10, 16.987]

rounded_list_of_floats = []

option = True


def round_up_or_down(list_of_floats, option):
    for individual_float in list_of_floats:
        if option == True:
            rounded_list_of_floats = rounded_list_of_floats + \
                ceil(individual_float)
        if option == False:
            rounded_list_of_floats = rounded_list_of_floats + \
                floor(individual_float)
        return rounded_list_of_floats


print(round_up_or_down(list_of_floats, False))
My interpreter runs this trace-back:
Quote:› python Bite153.py
Traceback (most recent call last):
File "Bite153.py", line 21, in <module>
print(round_up_or_down(list_of_floats, False))
File "Bite153.py", line 16, in round_up_or_down
rounded_list_of_floats = rounded_list_of_floats + \
UnboundLocalError: local variable 'rounded_list_of_floats' referenced before assignment

The problem is clearly with how I am referencing the rounded_list_of_floats variable.

So I Google 'UnboundLocalError' which turns up a doc by the UCSB titled:"Error: UnboundLocalError: local variable 'num' referenced before assignment". Based on my reading of this guide, I tried replacing line 13 with: rounded_list_of_floats += ceil(individual_float). No dice.

What kind of hints or advice could you people provide without giving me the solution entirely?

By the way, I originally got the idea to use the ceil() and floor() function from Real Python's guide called: How to Round Numbers in Python.
Reply
#2
(Feb-15-2020, 12:29 AM)Drone4four Wrote: What kind of hints or advice could you people provide without giving me the solution entirely?
OK. rounded_list_of_floats is an instance of builtin class list. You need to find appropriate method of list-class and use it instead of =/+=.
Reply
#3
A little bit simpler.
def round_up_or_down(list_of_floats, option):
    for individual_float in list_of_floats:
        if option:
            yield ceil(individual_float)
        else:
            yield floor(individual_float)


original_values = [1.5, 2.5, 3.5]
generator = round_up_or_down(original_values, True)
rounded_values = list(generator)
Your solution as normal function without implicit mutating a list on module level:
def round_up_or_down(list_of_floats, option):
    rounded_list_of_floats = []
    # never mutate implicit objects outside of the function
    # now rounded_list_of_floats inside the function is use for mutation
    for individual_float in list_of_floats:
        if option:
            rounded_list_of_floats.append(ceil(individual_float))
        else:
            rounded_list_of_floats.append(floor(individual_float))
    # pay attention for indentation. The return was before inside the for-block
    # which result into return from function after the first iteration of the for-loop.
    return rounded_list_of_floats
Your solution as normal function which mutates the list:
def round_up_or_down(list_of_floats, output, option):
    for individual_float in list_of_floats:
        if option:
            output.append(ceil(individual_float))
        else:
            output.append(floor(individual_float))


my_values = [1.5, 2.5, 3.5]
my_rounded_values = []  # it's a list
round_up_or_down(my_values, my_rounded_values, True)

print(my_rounded_values)
The cause why it's better to use scientific round is:
original_values = [0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]
ceil_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
scientific_round = list(map(round, original_values))

print('Sum of original values:', sum(original_values))
print('Sum of ceil values:', sum(ceil_values))
print('Sum of scientific rounded values:', sum(scientific_round))

print('Error between original and ceil values:', sum(ceil_values) - sum(original_values))
print('Error between original and scientific rounded values:', sum(scientific_round) - sum(original_values))
What you've learned in school is commercial rounding.
Scientific rounding ceil odd values at .5 and floor even values at .5.
It's defined in the IEEE 754
The function round in Python is using: to nearest, ties to even

You could have the control about rounding, if you use decimal.Decimal.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#4
Dear @DeaD_EyE: I appreciate the time and care you’ve invested in your reply to my original post. But you kinda ruined it for me because this was a personal challenge and you came up with 4 solutions that I wanted to do on my own. I specifically asked:

(Feb-15-2020, 12:29 AM)Drone4four Wrote: What kind of hints or advice could you people provide without giving me the solution entirely?

Thank you @scidam for your reply with your suggestion to explore list class methods. This is exactly what I needed to hear. I would have gone ahead and tried using the append or extend methods instead of =/+= but @DeaD_EyE already provided this solution. I’ll find a different exercise and make it more explicit next time here on this message board that I am not looking for solutions, just hints.
Reply
#5
An UnboundLocalError is raised when a local variable is referenced before it has been assigned. In most cases this will occur when trying to modify a local variable before it is actually assigned within the local scope. Python doesn't have variable declarations, so it has to figure out the scope of variables itself. It does so by a simple rule: If there is an assignment to a variable inside a function, that variable is considered local.

UnboundLocalError happend because when python sees an assignment inside a function then it considers that variable as local variable and will not fetch its value from enclosing or global scope when we execute the function. However, to modify a global variable inside a function, you must use the global keyword.
Reply
#6
Sorry, I had not seen this is an old question. Long since solved.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Rounding without using Python embedded functions NewCoder 3 2,677 Sep-06-2018, 10:23 PM
Last Post: woooee
  UnboundLocalError: local variable 'a' referenced before assignment fad3r 3 16,490 Jun-20-2018, 05:43 PM
Last Post: nilamo
  why am I getting "local variable 'x' referenced before assignment"? wlsa 6 9,066 Jun-16-2018, 05:31 PM
Last Post: buran
  variable referenced before assignment Niko047 4 22,899 Aug-04-2017, 07:55 PM
Last Post: nilamo
  local variable 'l' referenced before assignment... darkreaper1959 4 7,375 Jan-21-2017, 08:16 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020