Question

Hi im doing a udacity course on testing and I dont understand why im getting this problem with globals.

The thing is there is some implementation of queue I want to test. To do so I wrapp the methods with the post conditions [empty, full,enqueue,dequeue] using asserts and then proceed to do a random test on the structure with the wrapped functions to automate the testing.

For the assertions I need to keep track of the max items (size) of the queue and the actual items (elts) so i defined them as locals in function test().

Inside test() i define the wrapers and in the wrappers i use size and elts.

The thing i dont understand is if i make elts global inside the wrapper definition, then i got a NameError global name 'elts' is not defined at the wrapper But if i dont declare it as global in the wrapper then i get the UnboundLocalError of accessing elts before assigning a value to it.

I dont understand why a "Son" function declared in the body of a "Father" function cant see a local variable of the father and use it.

Here is the code

from queue_test import *
import random
import sys

def test():
    # Globals
    iters=100
    max_int=sys.maxint
    min_int=1
    elts=0
    size=0

    #Queue wrappers 
    # Wrapp the queue methods to include the assertions for automated testing
    def run_empty():
        temp=q.empty()
        if elts==0:
            assert temp==True
        else:
            assert temp==False
        return temp
    def run_full():
        temp=q.full()
        if elts==size:
            assert temp==True
        else:
            assert temp==False
        return temp
    def run_enqueue(val):
        temp=q.enqueue(val)
        if isinstance(val,int) and elts<size:
            elts+=1
            assert temp==True
        else:
            assert temp==False
        return temp
    def run_dequeue():
        temp=q.dequeue()
        if elts>0:
            elts-=1
            assert temp!=None and isinstance(temp,int)
        else:
            assert temp==None
        return temp

    # Random testing stuff
    def get_int(): # Return a random valid integer
        return random.randint(min_int,max_int)
    def get_command(): #Return a random valid command (string)
        return random.choice(["empty","full","enqueue","dequeue"])
    def run_random_command(): # Execute a random command
        c=get_command()
        if c=="empty":
            run_empty()
        elif c=="full":
            run_full()
        elif c=="enqueue":
            run_enqueue(get_int())
        elif c=="dequeue":
            run_dequeue()
        else:
            raise Exception("Error run command invalid command")
    def test_this(ncommands=100): # Randomly test a queue with ncommands commands
        run_empty()
        testi=get_int()
        run_enqueue(testi)
        testi2=run_dequeue()
        assert testi == testi2
        for c in range(ncommands):
            run_random_command()

    #Test Code: Do it random tests each one with a diferent random queue 
    for it in range(iters):
        size=get_int()
        elts=0
        q=Queue(size)
        test_this()
Was it helpful?

Solution

If you assign to a variable within a function, Python automatically makes it local. You'll need to explicitly mark them as global within the child functions. (In Python 3, you can use nonlocal for that.)

However, I can't help thinking that you should really be using a class here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top