0

It may seem a silly question: How deep in the loops and conditionals a global variable is used?

I have the following piece of code (the full code is provided at the end):

blockchain = []
index_ul = 0
...

def print_blockchain_elements():
    for block in blockchain:
        print('Outputting block:')
        print(block)

        if block == blockchain[index_ul]:
            print("block matches!")
            index_ul += 1

while True:
    print("Please choose: ")
    print("Press 1 for: Add a new transaction value")
    print("Press 2 for: Outputting the blockchain blocks")
    user_choice = get_user_choice()

    if user_choice == "1":
        tx_amount = get_transaction_value()
        add_value(tx_amount, get_last_blockchain_item())
    else:
        print_blockchain_elements()

When I run the code and the if statement if block == blockchain[index_ul]: is hit, i got the following error message:

Traceback (most recent call last):
  File "/home/v/blc.py", line 67, in <module>
    print_blockchain_elements()
  File "/home/v/blc.py", line 48, in print_blockchain_elements
    if block == blockchain[index_ul]:
UnboundLocalError: local variable 'index_ul' referenced before assignment

Now, i work in Visual Studio Code. when writing index_ul at blockchain[index_ul], VSC provides me hints for autocomplete, as it sees the variable. Why I get this local variable error when the variable is defined globally?

The rest of the code (I know that I have an endless while loop):

#!/usr/bin/env python3.7


# Initializing our blockchain list
blockchain = []
# This index value is used in the if statement in order to test correct functioning of the "for" loop when parsing list items
index_ul = 0

# The following declared function returns the value of the last positional element of the blockchain list

def get_last_blockchain_item():
    """ It returns the last value of the current blockchain"""
    return blockchain[-1] #the -1 is the first negative positional index, meaning, the last item in a list


# This function accepts 2 arguments.
# One of the arguments is required when calling the function (transaction_amount);
# Another one is an optional argument when calling the function (last_transaction);
# The optional argument is optional because it is a default argument, meaning that has its value defined when the function is declared
def add_value(transaction_amount, last_transaction=[1]): 
    """ Append a new value as well as the last blockchain value to the blockchain

    Arguments:
        :transaction_amount: The amount that should be added.
        :last_transaction: The last blockchain transaction (default [1])
    """
    # This code calls a method (.append) on an existing global variable of type string
    # append() method adds a value at the end of the list
    # In this case the added value is a list, marked with []
    blockchain.append([last_transaction, transaction_amount])


# The purpose of the following function is to: 1. Get user input at console 2. return the user input value as a float
def get_transaction_value():
    """ It returns the input of the user (a new transaction amount) as a float"""
    user_input = float(input("Amount: ")) #input() function is used to get a user input at console
    return user_input

def get_user_choice():
    user_input = input("Your choice: ")
    return user_input

def print_blockchain_elements():
    # The following loop goes through the list items and print each item individually
    # Then, the internal if statement verifies that the block/item parsed by for loop is indeed the next item in the list (by using indexes)
    for block in blockchain:
        print('Outputting block:')
        print(block)

        if block == blockchain[index_ul]:
            print("block matches!")
            index_ul += 1

# Get the first transaction input and add the value to the blockchain
tx_amount = get_transaction_value() #here I define a variable "tx_amount" with the value = to the result of the "get_user_input() function"
add_value(tx_amount) # Here, i call the function , specifying a value only for the "transaction_amount" variable of the function,
                     # the second argument of the function gets its default value last_transaction=[1]


while True:
    print("Please choose: ")
    print("Press 1 for: Add a new transaction value")
    print("Press 2 for: Outputting the blockchain blocks")
    user_choice = get_user_choice()

    if user_choice == "1":
        tx_amount = get_transaction_value()
        add_value(tx_amount, get_last_blockchain_item())
    else:
        print_blockchain_elements()
print(blockchain)

'''
wjandrea
  • 28,235
  • 9
  • 60
  • 81
vicSPP
  • 11
  • 1
  • 1
    You may need to add a line like `global your_variable_name` at the top of your methods, after the `def methodname():`, to use the global within methods. – Mike Furlender Mar 19 '20 at 13:32
  • 3
    If you assign to a name in a scope, it becomes local for the *entire* scope, not just the code that follows the assignment. Locality is determined when the function is defined, not when it is executed. – chepner Mar 19 '20 at 13:38
  • As far as I know, there is no limit on how deeply accessible the global environment is, beyond the arbitrary, implementation-imposed limits on how deeply nested your code can be in the first place. (Hitting the limits is virtually unheard of in hand-written code, only in machine-generated code, so it's not something you need to worry about.) – chepner Mar 19 '20 at 13:47
  • cool @Mike: it worked when i wrote: global index_ul (and after that index_ul = 0) right under def print_blockchain_elements() function declaration. so: if using a variable in a function (method), I have to declare it in the function as global; simply using global variable defined on top of the code works only if I use for and if statements by themselves (not as code to be run on a function/method), right? – vicSPP Mar 19 '20 at 13:51
  • 1
    Hint: use the search function https://stackoverflow.com/search?q=UnboundLocalError – bruno desthuilliers Mar 19 '20 at 13:53
  • yeap wjandrea, i got it now. thank you – vicSPP Mar 19 '20 at 14:13
  • @vicSPP yeah, that's correct – Mike Furlender Mar 19 '20 at 16:35

0 Answers0