Hi!

I've made a small program for an assignment and it works as it should. There's just one problem; the code contains two global variables. I won't pass the course unless I get rid of them and it's been bugging me for weeks.

The program:

##This program simulates a series of shooting competitions with participants found in a text file.

#modules
import random, time, sys

# classes
class Participant(object):
    """person with statistics"""
    
    # constructor
    def __init__(self, name, sigma, competitions, wins, wa_results):
        """Create participant with attributes"""
        self.name = name
        self.sigma = sigma
        self.competitions = competitions
        self.wins = wins
        self.wa_results = wa_results
    # methods
    def __str__(self):
        """String representation of the class."""
        return self.name + "/" + self.sigma + "/" + self.competitions + "/" + self.wins + "/" + self.wa_results

# functions
def read_file(database):
    """takes the information from the textfile and returns a list"""
    file1=[]
    for line in database.readlines(): 
        stats = line.split('/')         
        file1.append(stats)
    return file1

def make_object(file1):
    """makes an instance for each contestant and runs the shooting function"""

    for h in file1:
        try:
            temp = Participant(h[0],h[1],h[2],h[3],h[4])
            shooting(h[0], h[1])
        except ValueError and IndexError:
            print "Wrong format."
            time.sleep(1)
            sys.exit()
            

        
def season(file1):
    """creates one season, uses the shooting method within read_file function"""
    while True:
        try:
            comps_amount = int(raw_input("How many competitions in a season?"))
        
            if comps_amount > 0 and comps_amount < 101:
                break
            else:
                print "Must be at least 1 competition and at most 100."
        except ValueError:
            print "Try again with an integer this time..."
    winnerlist=[]
    print "======================================================="
    for comp in range(1, comps_amount+1):      
        print "Competition nr:", comp, "\n"
        global old_leader
        old_leader=0
        global tiedshot
        make_object(file1)
        print "======================================================="
        if (comp+1)%3==True and comp!=1:
            time.sleep(4)
        winnerlist.append(leader)
                                
                    
        

    print "Statistics:"    
    for word in set(winnerlist):
        """counts how many times a name appears in winnerlist"""
        wins=winnerlist.count(word)
        print word, "won", wins,
        if wins==1:
            print "competition."
        else:
            print "competitions."

def shooting(name, sigma):
    """creates one series of shots and results"""   
    print name,
    shotlist=[]
    for x in range(10):
        try:
            p = (110 - abs(int(random.normalvariate(0, int(sigma)))))
        except ValueError:
            print "Wrong format."
            time.sleep(1)
            sys.exit()
        if p < 20:
            p=0
        elif p == 110:
            p=100
        shot = p/20
        shotlist.append(shot)     
        print shot,
    shotlist.sort()
    del shotlist[0:2]
    shotsum = sum(shotlist)
    print "results =", shotsum
    global old_leader
    if shotsum > old_leader:
        global leader
        leader = name
        old_leader = shotsum

    
def main():
    """main function"""
    while True:
        while True:
            print """
            1. Simulate a season of shooting competitions.
            2. Exit programme.
            """
            try:
                choice = int(raw_input("Enter your choice:"))
            except ValueError:
                choice=None    
            if choice==1:
                break
            elif choice==2:
                print "Good bye."
                time.sleep(1)
                sys.exit()
            else:
                print "Choose 1 or 2..."
        try:
            database = open("participants.txt", 'r')
            file1= read_file(database)
            database.close()
    
            season(file1)
        except IOError:
            print "Can't find participants.txt, exiting."
            time.sleep(1)
            sys.exit()

    


    
# start program
main()

The txt-file that comes with, called participants.txt:

Bob/25/0/0/0
Bill/23/0/0/0
Billy Bob/32/0/0/0
Dick Cheney/34/0/0/0
Lee Harvey/28/0/0/0

Any help with how to replace the two global variables leader and old_leader would be much appreciated.

/Hydobat

I tried removing the global variable 'old_leader' and putting it as a parameter in every function that it involves but then it kept returning the value 0... Do you think something like that is the way to go?

By the way my presentation is due in 16 hours so some quick hints would mean a lot.

A standard design to avoid global variables is to define a class like this

class Competitions(object):
    def __init__(self):
        self. old_leader = 0
    def read_file(self, database):
        ...
    def make_object(self, file1):
        ...
    etc

if __name__ == "__main__":
    Competitions().main()

Thank you for replying! Just some questions.
Do I take every function and make it a method in the Competitions class? Even main()? Because that's what I've done now and the executer says "unbound method main() must be called with Competitions instance as first argument (got nothing instead)"

You don't need to put every function in the class, but it's the easiest thing to do. You must create an instance. If you replaced the call main() by Competitions().main() it should work (note that calling the class creates an instance).

I'm all for easy :). I'm probably missing something, but I can't see what. This is what I did so far:

#modules
import random, time, sys

class Competitions(object):

    def __init__(self):

      self. old_leader = 0

    def read_file(self, database):
        file1=[]
        for line in database.readlines(): 
            stats = line.split('/')         
            file1.append(stats)
        return file1        


    def make_object(self, file1):
        """makes an instance for each contestant and runs the shooting function"""
    
        for h in file1:
            try:
                shooting(h[0], h[1])
            except ValueError and IndexError:
                print "Wrong format."
                time.sleep(1)
                sys.exit()

    def season(self, file1):
        """creates one season, uses the shooting method within read_file function"""
        while True:
            try:
                comps_amount = int(raw_input("How many competitions in a season?"))
            
                if comps_amount > 0 and comps_amount < 101:
                    break
                else:
                    print "Must be at least 1 competition and at most 100."
            except ValueError:
                print "Try again with an integer this time..."
        winnerlist=[]
        
        print "======================================================="
        for comp in range(1, comps_amount+1):      
            print "Competition nr:", comp, "\n"
            #global old_leader
            make_object(file1)
            print "======================================================="
            if (comp+1)%3==True and comp!=1:
                time.sleep(4)
            winnerlist.append(leader)

        print "Statistics:"    
        for word in set(winnerlist):
            """counts how many times a name appears in winnerlist"""
            wins=winnerlist.count(word)
            print word, "won", wins,
            if wins==1:
                print "competition."
            else:
                print "competitions."

    def shooting(self, name, sigma):
        """creates one series of shots and results"""   
        print name,
        shotlist=[]
        for single in range(10):
            try:
                p = (110 - abs(int(random.normalvariate(0, int(sigma)))))
            except ValueError:
                print "Wrong format."
                time.sleep(1)
                sys.exit()
            if p < 20:
                p=0
            elif p == 110:
                p=100
            shot = p/20
            shotlist.append(shot)     
            print shot,
        shotlist.sort()
        del shotlist[0:2]
        shotsum = sum(shotlist)
        print "results =", shotsum
        #global old_leader
        if shotsum > old_leader:
            global leader
            leader = name
            old_leader = shotsum
            
    def main(self):
        """main function"""
        while True:
            while True:
                print """
                1. Simulate a season of shooting competitions.
                2. Exit programme.
                """
                try:
                    choice = int(raw_input("Enter your choice:"))
                except ValueError:
                    choice=None    
                if choice==1:
                    break
                elif choice==2:
                    print "Good bye."
                    time.sleep(1)
                    sys.exit()
                else:
                    print "Choose 1 or 2..."
            try:
                database = open("participants.txt", 'r')
                file1= read_file(database)
                database.close()
                season(file1)
            except IOError:
                print "Can't find participants.txt, exiting."
                time.sleep(1)
                sys.exit()
    
                                
                    

    


    


if __name__ == '__main__':

    Competitions.main()

The last line should be

Competitions().main()

Your mission is to understand why. Also, the word 'global' should not appear in your code.

I feel stupid. Why brackets? Because it's syntax for calling a class method in python I guess. I have now gotten rid of the globals.

New problem arrives. "'Competitions' object is not iterable"

I googled it and found this:

#required iterable elements
def __iter__(self):
return self.data.__iter__()

def __len__(self):
return len(self.data)

def __contains__(self, v):
return v in self.data

def __getitem__(self, v):
return self.data[v]

I don't really understand it, is it necessary for my code?

No, you probably entered something different from what I said above. Now good luck for your presentation, I can't help you more because it's very late here. bye.

You were probably right, I got that working now. Thank you so much for helping.

Now the first problem seem to almost repeat itself.

#modules
import random, time, sys

class Competitions(object):

    def __init__(self):

        self.old_leader = 0
        self.leader = 0


    def read_file(self, database):
        file1=[]
        for line in database.readlines(): 
            stats = line.split('/')         
            file1.append(stats)
        return file1        


    def make_object(self, file1):
        """makes an instance for each contestant and runs the shooting function"""
    
        for h in file1:
            try:
                Competitions().shooting(h[0], h[1])
            except ValueError and IndexError:
                print "Wrong format."
                time.sleep(1)
                sys.exit()

    def season(self, file1):
        """creates one season, uses the shooting method within read_file function"""
        while True:
            try:
                comps_amount = int(raw_input("How many competitions in a season?"))
            
                if comps_amount > 0 and comps_amount < 101:
                    break
                else:
                    print "Must be at least 1 competition and at most 100."
            except ValueError:
                print "Try again with an integer this time..."
        winnerlist=[]
        
        print "======================================================="
        for comp in range(1, comps_amount+1):      
            print "Competition nr:", comp, "\n"
            Competitions().make_object(file1)
            print "======================================================="
            if (comp+1)%3==True and comp!=1:
                time.sleep(4)
            winnerlist.append(leader)

        print "Statistics:"    
        for word in set(winnerlist):
            """counts how many times a name appears in winnerlist"""
            wins=winnerlist.count(word)
            print word, "won", wins,
            if wins==1:
                print "competition."
            else:
                print "competitions."

    def shooting(self, name, sigma):
        """creates one series of shots and results"""   
        print name,
        shotlist=[]
        for single in range(10):
            try:
                p = (110 - abs(int(random.normalvariate(0, int(sigma)))))
            except ValueError:
                print "Wrong format."
                time.sleep(1)
                sys.exit()
            if p < 20:
                p=0
            elif p == 110:
                p=100
            shot = p/20
            shotlist.append(shot)     
            print shot,
        shotlist.sort()
        del shotlist[0:2]
        shotsum = sum(shotlist)
        print "results =", shotsum
        if shotsum > old_leader:
            leader = name
            old_leader = shotsum
            
    def main(self):
        """main function"""
        while True:
            while True:
                print """
                1. Simulate a season of shooting competitions.
                2. Exit programme.
                """
                try:
                    choice = int(raw_input("Enter your choice:"))
                except ValueError:
                    choice=None    
                if choice==1:
                    break
                elif choice==2:
                    print "Good bye."
                    time.sleep(1)
                    sys.exit()
                else:
                    print "Choose 1 or 2..."
            try:
                database = open("participants.txt", 'r')
                file1= Competitions().read_file(database)
                database.close()
                Competitions().season(file1)
            except IOError:
                print "Can't find participants.txt, exiting."
                time.sleep(1)
                sys.exit()

if __name__ == '__main__':

    Competitions().main()

When I run it, it says :

"in shooting
if shotsum > old_leader:
UnboundLocalError: local variable 'old_leader' referenced before assignment" (line 86.)

I thought old_leader was assigned in the constructor? Does anyone see what's wrong?

I thought old_leader was assigned in the constructor?

Look again. You declared self.old_leader, so what is the difference in a class structure between self.old_leader and just old_leader.

try.
if shotsum > self .old_leader:

Can you post participants.txt Or just a part of it,so we can se format that goes inn.

Not sure, but I think self.old_leader is used in methods to get class variables? So you are implying I should add 'self.' to all the 'old_leader's (and 'leader's)?

In that case I did that, and it works, except for every loop 'self.old_leader' retakes the value 0. Is there a way to fix this?

try.
if shotsum > self .old_leader:

Can you post participants.txt Or just a part of it,so we can se format that goes inn.

As I thought woooee meant:).

It's in the first post but here it is again:
Bob/25/0/0/0
Bill/23/0/0/0
Billy Bob/32/0/0/0
Dick Cheney/34/0/0/0
Harvey Lee/28/0/0/0

Hooray! I figured out the rest. God bless you guys, you are lifesavers.

If you're interested I changed Competitions().method() to self.method() and put self.old_leader=0 in between the shootings.

#modules
import random, time, sys

class Competitions(object):

    def __init__(self):

        self.old_leader = 0
        self.leader = 0


    def read_file(self, database):
        file1=[]
        for line in database.readlines(): 
            stats = line.split('/')         
            file1.append(stats)
        return file1        


    def make_object(self, file1):
        """makes an instance for each contestant and runs the shooting function"""
    
        for h in file1:
            try:
                self.shooting(h[0], h[1])
            except ValueError and IndexError:
                print "Wrong format."
                time.sleep(1)
                sys.exit()

    def season(self, file1):
        """creates one season, uses the shooting method within read_file function"""
        while True:
            try:
                comps_amount = int(raw_input("How many competitions in a season?"))
            
                if comps_amount > 0 and comps_amount < 101:
                    break
                else:
                    print "Must be at least 1 competition and at most 100."
            except ValueError:
                print "Try again with an integer this time..."
        winnerlist=[]
        
        print "======================================================="
        for comp in range(1, comps_amount+1):
            
            print "Competition nr:", comp, "\n"
            self.make_object(file1)
            print "======================================================="
            if (comp+1)%3==True and comp!=1:
                time.sleep(4)
            winnerlist.append(self.leader)
            self.old_leader=0
        print "Statistics:"    
        for word in set(winnerlist):
            """counts how many times a name appears in winnerlist"""
            wins=winnerlist.count(word)
            print word, "won", wins,
            if wins==1:
                print "competition."
            else:
                print "competitions."

    def shooting(self, name, sigma):
        """creates one series of shots and results"""   
        print name,
        shotlist=[]
        for single in range(10):
            try:
                p = (110 - abs(int(random.normalvariate(0, int(sigma)))))
            except ValueError:
                print "Wrong format."
                time.sleep(1)
                sys.exit()
            if p < 20:
                p=0
            elif p == 110:
                p=100
            shot = p/20
            shotlist.append(shot)     
            print shot,
        shotlist.sort()
        del shotlist[0:2]
        shotsum = sum(shotlist)
        print "results =", shotsum
        
        if shotsum > self.old_leader:
            self.leader = name
            self.old_leader = shotsum
        
            
    def main(self):
        """main function"""
        while True:
            while True:
                print """
                1. Simulate a season of shooting competitions.
                2. Exit programme.
                """
                try:
                    choice = int(raw_input("Enter your choice:"))
                except ValueError:
                    choice=None    
                if choice==1:
                    break
                elif choice==2:
                    print "Good bye."
                    time.sleep(1)
                    sys.exit()
                else:
                    print "Choose 1 or 2..."
            try:
                database = open("participants.txt", 'r')
                file1= self.read_file(database)
                database.close()
                self.season(file1)
            except IOError:
                print "Can't find participants.txt, exiting."
                time.sleep(1)
                sys.exit()
if __name__ == '__main__':

    Competitions().main()

If you can pick out some fundamental mistake please tell me:). I'm going to sleep for a while. Good night.

i have no idea but i would have thought that just using a return for each would work? excuse me if im giving a stupidly wrong answer

i have no idea but i would have thought that just using a return for each would work? excuse me if im giving a stupidly wrong answer

That might have worked if done properly, but I couldn't do it.

I passed the course today so thank you again, I'll mark this thread solved.

This question has already been answered. Start a new discussion instead.