0

self teaching myself how to code and starting with this book and a Udemy course.

have been working on this practice project for 2 days now and I keep running into "Local variable 'streaks' not used when I have the streak counter placed inside the htcheck function even though I'm Cleary defining the variable, I tried placing the streak variable outside of the function at the top of the code to declare as it a global value but that still doesn't work and then I get the "Shadow name" error.

what the code should be doing is flipping a coin 10000 times then checking for streaks of 6 then present the user with how many streaks of 6 occurred and a percent value of how often a streak of 6 was, I'm sure a lot of you have seen this question been asked before as it's from Al Sweigart's Automate The Boring Stuff with python 2nd edition <- I just cant find the answer to my specific error hence this post.


I just need help with figuring out why my variable ' streaks = 0 ' isn't working as shown below. and why it doesn't work as a global variable declared where I have heads tails and x. I would prefer a solution that keeps streaks inside the htcheck function but i'm open to any and all solutions.

Thank you in advance.

# Automate Python - Coin Flips Streaks
heads = []
tails = []
x = 0


#Flips a coin, then stores result into respective list
def coinflip():
    y = random.randint(0, 1)
    if y == 0:
        heads.append('H')
        tails.clear()
    elif y == 1:
        tails.append('T')
        heads.clear()

#checks if list len is 6 then clears and adds +1 to streak
def htcheck():
    streaks = 0
    if len(heads) == 6:
        streaks = streaks + 1
        heads.clear()
    elif len(tails) == 6:
        tails.clear()
        streaks = streaks + 1


while x < 10000:
    x = x + 1
    coinflip()
    htcheck()

print('# Streaks of 6: ", streaks)

  • `streaks` needs to be set as a global if you are modifying its value in one function and reading it in another. You have not defined it in global scope. Also your print statement has mismatched quote types. – Random Davis Dec 06 '22 at 18:52
  • 1
    Alternately, because `streaks` is _local_ to the function, you could `return streaks` in the function, and use that to increment a counter in the global scope. See: [Short description of the python scoping rules](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) – G. Anderson Dec 06 '22 at 19:01
  • @RandomDavis streaks was defined at the top before like i said in my post, to my knowledge that would make it a global var, when it was set to a global var I got a shadow name error and code wouldn't compile and run, also aware of the quotes, just input that to make it clear that im trying to print streaks, but thanks for pointing it out! – Michele Staffiere Dec 06 '22 at 19:46
  • @G.Anderson so something like this? def htcheck(): streaks = 0 if len(heads) == 6: streaks = streaks + 1 heads.clear() elif len(tails) == 6: tails.clear() streaks = streaks + 1 return streaks – Michele Staffiere Dec 06 '22 at 19:47
  • One thing to note: Unless you declare `global streaks` inside the function, putting it at the top it doesn't automatically make it global. There can still be a local variable with the same name inside a function – G. Anderson Dec 06 '22 at 19:52
  • 1
    @G.Anderson ah thank you so much for the note! - i did the following and it now works as intended. Going to read what you linked as well about scoping rules. Thank you again change made: def htcheck(): global streaks if len(heads) == 6: streaks = streaks + 1 heads.clear() elif len(tails) == 6: tails.clear() streaks = streaks + 1 now i get my expected output: # Streaks of 6: 147 – Michele Staffiere Dec 06 '22 at 19:55
  • @MicheleStaffiere by "set as global" that's exactly what I meant. But I guess you assumed I meant putting it at the top of the file or function, without using the `global` keyword. I suggest you just google it next time rather than assuming. – Random Davis Dec 06 '22 at 19:57
  • I'm glad you were able to use the hint to get the global version working, but I would urge you to also try to make it work without using globals, see my answer below. See also [Why are global variables evil?](https://stackoverflow.com/questions/19158339/why-are-global-variables-evil) for more information – G. Anderson Dec 06 '22 at 20:05
  • @RandomDavis I clearly stated in my post that to my knowledge so far (including from what I googled) that streaks was set as a global var based on it's placement outside the function, and tested it being both inside and outside the function. – Michele Staffiere Dec 07 '22 at 21:46

1 Answers1

1

While you can use global variables for something like this, I generally prefer using return statements and tracking the variables separately for easier debugging and readability

Something like this is an option

# Automate Python - Coin Flips Streaks
heads = []
tails = []
num_streaks = 0
#here we eliminate the need for a counter variable x by using a for loop instead of a while loop below, instead creating a counter for our streaks

#Flips a coin, then stores result into respective list
def coinflip():
    y = random.randint(0, 1)
    if y == 0:
        heads.append('H')
        tails.clear()
    elif y == 1:
        tails.append('T')
        heads.clear()

#checks if list len is 6 then clears and adds +1 to streak
def htcheck():
    streaks = 0
    if len(heads) == 6:
        streaks = streaks + 1
        heads.clear()
    elif len(tails) == 6:
        tails.clear()
        streaks = streaks + 1
    #here we return the local variable instead of trying to use the global scope
    return streaks

#using a for instead of a while loop is a bit of a stylistic choice but can prevent problems arising from forgetting a `break` condition or messing up counter incrementation
for x in range(1000):
    coinflip()
    #here we add to the streak counter we declared in the outer scope by using the local variable returned from the function
    num_streaks += htcheck()

print('# Streaks of 6: ', num_streaks)
G. Anderson
  • 5,815
  • 2
  • 14
  • 21