Shadow name error and Local variable not used - python

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)

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)

Related

using the collatz sequence in dictionaries

I'm pretty new to python and currently, I'm trying to learn dictionaries. I'm trying to write a program that asks the user for a number, and then outputs the number less than or equal to the one the user entered with the longest Collatz sequence.
This is what I currently have right now, but I don't know why it won't work.
def collatz(number):
segLength = {}
for i in range(1, number + 1):
current = 1
count = 0
while current != 1:
if current % 2 == 0:
current = number / 2
elif current % 2 != 0:
current = (3 * number + 1)
count += 1
segLength[i] = count
value = list(segLength.values())
key = list(segLength.keys())
x = max(value)
index = value.index(x)
output = key[index]
return output
result = collatz(number)
print = result
Each iteration of your for loop, you set current = 1, so current != 1 will always be False and you'll skip the while.
It looks like you want to calculate the collatz sequence for each number so I'm guessing you want to instead set current = i.
Then, for each iteration of your for loop, current will have the number you want to reduce to 1 and count the number of steps it takes. To make this work, you'll want to change:
current = number / 2
(and the corresponding 3n+1 line in the elif) to
current = current / 2
because number is always going to be the number you passed into the function at the start, not the number you're trying to run a collatz sequence on this iteration
It looks like it should work otherwise!
EDIT: you should also call print rather than assign to it as Barmar said.

How to add to a counter using decisions and input

I have tried for the past hour to make this program. The aim of the program is to record the preference of food for 15 people and count and display the total at the end. Each person can only choose 1 food. Here is where I'm stuck. None of this code seems to work(add to the counters). If anybody can help or send me the correct code it would be greatly appreciated:)
#Choices of food for the customers
meatplate_1 = 0
fishplate_2 = 0
vegetableplate_3 = 0
#Decision making as input data
for i in range (15):
num = int(input("What do you want for lunch?"))
if num == 1 :
meatplate + 1
print(meatplate_1)
As already mentioned by #0x5453 in comments, you should increment meatplate_1 variable.
And, If condition should come inside for loop, increment should be done by += operator.
You can refer below code.
#Choices of food for the customers
meatplate_1 = 0
fishplate_2 = 0
vegetableplate_3 = 0
#Decision making as input data
for i in range (15):
num = int(input("What do you want for lunch?"))
if num == 1 :
meatplate_1+=1
elif num==2:
fishplate_2+=1
elif num==3:
vegetableplate_3+=1
else:
pass
print(meatplate_1)

Counting Heads and Tails in a coin flip program

For my assignment, I have to use Functions within Python to simulate a coin flip. I managed to get the coin flip to showcase heads and tales for the amount the user has inputted. However, for the next portion, I have to get the program to read how many times Heads and Tails appeared. The error I am getting is
'NameError: name 'heads' is not defined'.
import random
def main():
tosses = int(input("Please enter the amount of coin tosses:"))
coin(tosses)
count = 0
heads = 0
tails = 0
def coin(tosses):
for toss in range(tosses):
if random.randint(1, 2) == 1:
print('Heads')
heads += 1
count += 1
else:
print('Tails')
heads += 1
count += 1
print (heads)
print (tails)
main()
Problem
heads was defined out of the scope of the function coin.
Solution
Try defining the variables inside the function, then returning them. Note: the same had to be done with main.
import random
def main():
tosses = int(input("Please enter the amount of coin tosses:"))
coin(tosses)
heads, tails, count = coin(tosses)
return heads, tails
def coin(tosses):
count = 0
heads = 0
tails = 0
for toss in range(tosses):
if random.randint(1, 2) == 1:
print('Heads')
heads += 1
count += 1
else:
print('Tails')
tails += 1 # note you had this say heads before
count += 1
return heads, tails, count
heads, tails = main()
print(heads)
print(tails)
More on why this problem occurred
When you use def and create a new function, all of the variables in that function are accessible just to that function.
What was happening to you, is that you were trying to update the heads variable with heads += 1, but the function literally didn't know what the variable you were referring to is! (That variable was defined in main, and is only accessible from within the main function.)

list index out of range-python

I'm trying to make an hangman game where you can type a specific word into it.
I came across a problem when trying to make a code which count the number of same letters in the word. For example, 'taste' will have two ts.
The program would count the letter which will be used for mathematical sums so the letter can be entered twice but no more.
I came across the list index is out of range problem in the code below.
def nolettercheck():
global list45 #list of variable within code (so they can be accessed)
global list1
global countonce
global count0
global count1
global count2
global count3
global count4
global count5
global count6
global count7
global count8
global count9
if len(list1) == 1: #makes sure list is in range
if list1.count(list1[0]) > 1: """count how many letter in word and if above 1 it continues
(although it doesn't work perfectly yet BTW do not spoil
this answer for me unless
you have to)."""
count0 = list1.count(list1[0])#create variable for number of same letters
list45.insert(0,list1[0])#insert the letter into another list for comparison
if len(list1) == 2 or len(list1) < 2: """repeats with next letter until
similar statement =false"""
if list1.count(list1[1]) > 1:
count1 = list1.count(list1[1])
list45.insert(1,list1[1])
if len(list1) == 3 or len(list1) < 3:
if list1.count(list1[2]) > 1:
count2 = list1.count(list1[2])
list45.insert(2,list1[2])
if len(list1) == 4 or len(list1) < 4:
if list1.count(list1[3]) > 1:
count3 = list1.count(list1[3])
list45.insert(3,list1[3])
if len(list1) == 5 or len(list1) < 5:
if list1.count(list1[4]) > 1:
count4 = list1.count(list1[4])
list45.insert(4,list1[4])
if len(list1) == 6 or len(list1) < 6:
if list1.count(list1[5]) > 1:
count5 = list1.count(list1[5])
list45.insert(5,list1[5])
if len(list1) == 7 or len(list1) < 7:
if list1.count(list1[6]) > 1:
count6 = list1.count(list1[6])
list45.insert(6,list1[6])
The code continues so it can do up to a ten letter word. This code is suppose to store the no of letter into a variable (which will be turned into a list later down the line although I might change that further on). It should also store the letter (if there is more than one letter).
The error specifically focuses on similar lines to if list1.count(list[6]) > 1:.
I did come across this error before and if len(list1) == 7 or len(list1) <7: worked (as it stopped checking for imaginary values in the list). So I am quite befuddled about this.
here's a way to get a dictionary of letter counts from a word. there are more 'pythonic' ways of doing this but if you're just getting started, this may help you out.
a = 'somestring'
letter_count_dict = {}
for letter in set(a):
letter_count_dict[letter] = a.count(letter)
the distinct letters in the word are
set(a) #set takes the distinct values. If you want a list of distinct values, an easy way to do it is list(set(a)) but since sets are iterable you don't usually need to do this.
and given a letter, l, the number of times it occurs is
letter_count_dict[l] #if l='s', then this would output 2
once you have the counts, you can choose what to do with them...loop and find the ones with greater than one occurrence, etc.. good luck.

Division by values in a dictionary (Python)

I am building a prime generator (I know, another one and probably not a very good one at that, but that is for another question.) I am using a dictionary for my collection of primes and ignoring composites by dividing by the previous primes. However it doesn't seem to be iterating properly in the final stage of the function and I get a number of incorrect results. isWhole is a self explanatory call to another function. This is my code where x = the number of primes to be generated:
def prime_generator(x):
count = 2
counter = 2
p = {1: 2}
while len(p) <= x:
if count % 2 == 0:
count += 1
continue
test1 = (math.sqrt(count))
if isWhole(test1) == True:
count += 1
continue
for k, a in p.items():
if count % a == 0:
break
else:
p[ counter ] = count
counter += 1
break
count += 1
return p
Your design intent is not entirely clear, but you may be intending to have the else clause apply to the for loop rather than the if statement. Try un-indenting the entire else clause so that it only runs if the loop terminates without hitting a break.

Categories