Foxes
Foxes

Reputation: 1237

How to use an integer variable as a parameter for a function?

I'm trying to make a piece of code that will count up votes for three different candidates, and I'm using a function that uses the variable name (either A, B or C) as a parameter.

I'm trying to have it so that whenever a vote is counted for that candidate, it will call the function to increase the variable for that candidate by 1. However, with every way I've tried all 3 candidates will always have 0 votes counted, unless I completely remove the function.

I've tried several different ways of making the variables global variables but they all gave the same results.

A = 0
B = 0
C = 0

def after_vote(letter):
    letter = letter + 1
    print("Thank you for your vote.")

def winner(winner_letter, winner_votes):
    print("The winner was", winner_letter, "with", str(winner_votes), "votes.")

while True:
    vote = input("Please vote for either Candidate A, B or C. ").upper()
    if vote == "A":
        after_vote(A)
    elif vote == "B":
        after_vote(B)
    elif vote == "C":
        after_vote(C)
    elif vote == "END":
        print("Cadidate A got", str(A), "votes, Candidate B got", str(B), "votes, and Candidate C got", str(C), "votes.")
        if A > B and A > C:
            winner("A", A)
            break
        elif B > A and B > C:
            winner("B", B)
            break
        elif C > A and C > B:
            winner("C", C)
            break
        else:
            print("There was no clear winner.")
            break
    else:
        print("Please input a valid option.")

Upvotes: 4

Views: 4365

Answers (4)

zvone
zvone

Reputation: 19372

First of all, the idea is wrong. You don't want to handle global variables and pass names around. It could be done, but it is a bad idea.

A better option is to pass the variable to be modified to the function. However, the trick with integers is that they are immutable, so you cannot pass an integer to be modified by the function, as you would in C for instance.

What is left is either:

  • pass a value to the function, return the modified value from the function; or
  • pass a mutable object holding the value to the function

That was the theory, here is how to do it...

Solution 1: pass one value, return the modified value

def after_vote(value):
    print("Thank you for your vote.")
    # Instead of modifying value (impossible), return a different value
    return value + 1

A = after_vote(A)

Solution 2: pass a "mutable integer"

class MutableInteger:
    def __init__(value):
        self.value = value

A = MutableInteger(0)

def after_vote(count):
    # Integers cant be modified, but a _different_ integer can be put
    # into the "value" attribute of the mutable count object
    count.value += 1
    print("Thank you for your vote.")

after_vote(A)

Solution 3: pass a (mutable!) dictionary of all votes

votes = {'A': 0, 'B': 0, 'C': 0}

def after_vote(votes, choice):
    # Dictionaries are mutable, so you can update their values
    votes[choice] += 1
    print("Thank you for your vote.")

after_vote(votes, "A")

Solution 4 (the worst!): actually do what you asked for

def after_vote(letter):
    # Global variables are kept in a dictionary. globals() returns that dict
    # WARNING: I've never seen code which does this for a *good* reason
    globals()[letter] += 1
    print("Thank you for your vote.")

Upvotes: 6

AmphotericLewisAcid
AmphotericLewisAcid

Reputation: 2299

The easiest way to do this would be to use a dict, if no two candidates will share the same name.

candidates = {"A":0, "B":0, "C":0}

From there, you could set up a function to look up a value in the dictionary and increment it:

def update_vote(candidate):
    candidates[candidate] += 1

Or heck, you could just update the votes in-place rather than calling a function with:

candidates[candidate] += 1

A much more pythonic way of doing this would be to make each candidate an object that can update its own vote count.

class Candidate(object):
    def __init__(self):
        # This is the "constructor" for the object.
        # It is run whenever an instance of this object is created.
        # We want it to "spawn in" with zero votes.
        self.vote_count = 0
    def update_vote(self):
        self.vote_count += 1

This seems to be closer to what you were getting at in your initial post. You would create an object as follows:

A = Candidate()
B = Candidate()
C = Candidate()

And then, in your main loop, you would just tell each object to update itself:

if vote == "A":
    A.update_vote()

Finally, when you're tallying up the votes, you would just ask each object to give you their "vote" count:

if A.vote_count > B.vote_count and A.vote_count > C.vote_count

Upvotes: 2

Laurent LAPORTE
Laurent LAPORTE

Reputation: 22992

In your situation, it is better to define 3 function, one for each candidate:

A = 0
B = 0
C = 0

def after_vote_A():
    global A
    A += 1
    print("Thank you for your vote.")

def after_vote_B():
    global B
    B += 1
    print("Thank you for your vote.")

def after_vote_C():
    global C
    C += 1
    print("Thank you for your vote.")

Don’t forget to use the keyword global or else you define a local variable.

An alternative is to store votes in a dict:

votes = {'A': 0, 'B': 0, 'C': 0}

def after_vote(letter):
    votes[letter] += 1
    print("Thank you for your vote.")

Démonstration:

after_vote('A')
after_vote('B')
after_vote('A')
after_vote('A')
print(votes)

You get:

Thank you for your vote.
Thank you for your vote.
Thank you for your vote.
Thank you for your vote.
{'A': 3, 'B': 1, 'C': 0}

Upvotes: 2

Ali Yılmaz
Ali Yılmaz

Reputation: 1695

You need to pass a mutable data type into function, so that you can modify it. Try wrapping your candidates into a list or dictionary.

candidates = {'A':0, 'B':0, 'C':0}

def after_vote(letter):
    global candidates
    if letter in candidates:
        candidates[letter] += 1
        print("Thank you for your vote.")
    else:
        print("No such candidate: Your vote is invalid.")

Upvotes: 1

Related Questions