Function won't be called upon - python

When I run the program everything is fine until the password validity function is ran and all the conditions of length and uppercase and lowercase are equal to true. What the program is supposed to do here is run the creditcard function but it doesn't as seen here:
if length and upper and lower == True:
creditcard()
It doesn't give me any errors or syntax messages about it when the conditions of length, upper, and lower case are all true but still will not run the creditcard function, the program simply ends. however when any of the conditions of length uppercase or lowercase are not met using or logic then "The password's invalid" is still successfully printed.
def creditcard():
balence = input("What is your credit card balence this month")
choice = input("Would you like to make a payment or make the standard deduction? y or n")
intrest = .1596/12
amountdue = balence*interest
enter code here
if choice == "y":
payment = input("How much would you like to pay?")
if payment == "n":
if 0.3 * amountdue>25:
payment = 0.3 * amountdue
elif 0.3 * amountdue<25:
payment = 25
balence-=payment
print("Your balence is now", balence)
def validity(password):
length=()
upper=()
lower=()
if len(password)<5:
length = True
else: lenghth = False
for char in password:
if char.isupper():
upper = True
else: upper = False
for char in password:
if char.islower():
lower = True
else: lower = False
if length and upper and lower == True:
creditcard()
if length or upper or lower == False:
print("The password's invalid")
password=""
def main():
password=""
while password=="":
password= input("Please enter a valid password")
validity(password)`enter code here`
main()

The problem is that your if condition is never being met. You can check this quickly by putting something like print("Going to call creditcard") between the if and creditcard() lines. You'll see the message is never printed. To find out why, you could print the values of length, upper and lower before the ifs to see if the values are what you expect.
That's how I'd recommend trying to diagnose your problem with quick and dirty debugging. As for explaining what your problem actually is:
When you do for char in password this is going through each character in the password and then running the test for is upper/lower for that character. This means if you have the password aB then on the first run it will check a and so will set lower to True, but then it will test the next character, B, and set lower to False. So basically, it's only checking the case of the last character, and as a single character can't be both upper and lower your condition for upper and lower being true will never be met.
A better way to do it is to initialise all the conditions as being false and then set them to true when met, e.g.
upper = False
for char in password:
if char.isupper():
upper = True
­
Edit: As deceze pointed out, you also need to be careful with the line if length or upper or lower == False. Because that is not the same as if (length == False) or (upper == False) or (lower == False). Instead, it evaluates it like: if length or upper or (lower == False), and an or operator returns true if either condition is true.
As an example, if the length = False, upper = False and lower = True, the condition would then be: if False or False or (True == False), which gets evaluated to False or False or False which gets evaluated to False. This may be a bit confusing, check the link deceze commented for a fuller description, but in your case a simpler way would be to just use an else.
There are a few more issues I can see, I realise you may not have got to this stage of checking your code yet, but just a heads up:
There are a few typos which can trip you up if you spell a variable differently throughout your code.
I assume that you want to length to be greater than 5? Currently you're using less than.
When you use input() the value is always a string (text) this will cause problems when you try to do your calculations with balance and payment. It's easy to overcome by telling Python to cast the data to a number by using int() for whole numbers, or float() for decimals, like so: balance = int(input("What is your credit card balance this month?"))
And finally (of the things that I can see), it looks like you're trying to make a loop so the user can keep re-entering the password if their previous attempt was invalid? But the condition on the while loop is just checking if the password is empty, so will terminate as soon as the user types in any password. You could create a new boolean called created_password initialised to False and use that as the condition? If I were you I'd do this by making validity just return True or False (depending on if the password is or isn't valid), then call creditcard() from main once out of the while loop.
I'd recommend you try to work through the errors yourself, this way you'll be able to actually see the error messages and learn how to fix them. If you get stuck I've made a version which works here: https://trinket.io/python3/b6b8c0ca31 which you can compare with your code.
Or a slightly more compact version: https://trinket.io/python3/d934a3a48e

Related

How to divide variable from input by two

On line 7 and 14 I cant figure out how to divide the variable.
import keyboard
import random
def main(Number, Start):
Number = random.randrange(1,100)
Start = False
QA = input('Press "K" key to begin')
if keyboard.is_pressed('K'):
Start = True
input('I"m thinking of a random number and I want that number divisible by two')
print(Number)
input('Please divide this by two. *IF IT IS NOT POSSIBLE RESTART GAME*\n')
if QA == int(Number) / 2:
print('.')
else:
print('.')
main(Number=' ' ,Start=' ')
What you probably want:
Pick a random number
Make user divide this number by two (?)
Do something based on whether the guess is correct
What is wrong with your code:
You are not picking a number divisible by two. The easiest way to ensure that your number is, indeed, divisible by two, is by picking a random number and then multiplying it by two: my_number = 2 * random.randrange(1, 50). Note the change in the range. Also note that the upper limit is not inclusive, which may be not what your meant here. A typical check for divisibility by N is using a modulo operator: my_number % N == 0. If you want users to actually handle odd numbers differently, you would need to write a separate branch for that.
input returns a string. In your case, QA = input('Press "K" key to begin') returns "K" IF user has actually done that or random gibberish otherwise. Then you are checking a completely unrelated state by calling keyboard.is_pressed: what you are meant to do here is to check whether the user has entered K (if QA == "K") or, if you just want to continue as soon as K is pressed, use keyboard.wait('k'). I would recommend sticking to input for now though. Note that lowercase/uppercase letters are not interchangeable in all cases and you probably do not want users to be forced into pressing Shift+k (as far as I can tell, not the case with the keyboard package).
input('I"m thinking of does not return anything. You probably want print there, possibly with f-strings to print that prompt along with your random number.
input('Please divide this by two. does not return anything, either. And you definitely want to store that somewhere or at least immediately evaluate against your expected result.
There is no logic to handle the results any differently.
Your function does not really need any arguments as it is written. Start is not doing anything, either.
Variable naming goes against most of the conventions I've seen. It is not a big problem now, but it will become one should you need help with longer and more complex code.
Amended version:
import random
import keyboard
def my_guessing_game():
my_number = random.randrange(1, 50) * 2
# game_started = False
print('Press "K" to begin')
keyboard.wait('k')
# game_started = True
print(f"I'm thinking of a number and I want you to divide that number by two. My number is {my_number}")
user_guess = input('Please divide it by two: ')
if int(user_guess) == my_number / 2:
# handle a correct guess here
print('Correct!')
pass
else:
# handle an incorrect guess here
pass
Alternatively, you can use the modulo operator % to test whether Number is divisible by 2:
if Number % 2 == 0:
print('.')
else:
print('.')
This will check whether the remainder of Number divided by 2 is equal to 0, which indicates that Number is divisible by 2.

[Random String Generator]Getting stuck in a loop on else condition

So (as you will probably see from my code) I am a beginner at Python (version 3.8.3) and enjoying it very much so far, and I have challenged myself on several different beginner projects. I am currently making a random string generator (i.e. a password generator, hence the use of the secrets module).
# Password Generator
import secrets, string
print("Welcome to the generator. Please specify your requirements")
print("A. All Characters;\nB. No Numbers;\nC. No Punctuation\nPlease choose the appropriate letter for your needs.")
userInput = input()
def userWelcome():
if userInput.lower() == "a":
generatePass = string.ascii_letters + string.digits + string.punctuation
print("How long do you want your string to be?")
stringRange = int(input())
print( "".join(secrets.choice(generatePass) for _ in range(stringRange)) )
elif userInput.lower() == "b":
generatePass = string.ascii_letters + string.punctuation
print("How long do you want your string to be?")
stringRange = int(input())
print("".join(secrets.choice(generatePass) for _ in range(stringRange)))
elif userInput.lower() == "c":
generatePass = string.ascii_letters + string.digits
print("How long do you want your string to be?")
stringRange = int(input())
print("".join(secrets.choice(generatePass) for _ in range(stringRange)))
else:
print("Not an option! Let's try again.")
userWelcome()
userWelcome()
However, my problem is what to do if the user inputs an incorrect option. As you can see, with the else statement I assume what they filled in does not match any of the earlier options - and so I want to try to rerun the generator again (so I try to call userWelcome again in the else statement).
However, when I type in for example 12 as input, my shell starts to output my string (Not an option Let's try again) literally a thousand times like it is stuck in a loop. I am wondering what I am doing wrong exactly.
What I have tried:
(1) So I have tried to solve this input problem first with try and except, running the except when there is a ValueError but that only works for numbers and I did not manage to rerun userWelcome()
(2) I have tried to create a elif statement in which I check the input for integers, however that also gets stuck in a loop. Code:
elif userInput.isalpha() == False:
print("Not an option! Let's try again.")
userWelcome()
Anyway, I hope that explains it well. I have been busy with this for a few hours now and I thought I'd ask this. Maybe it's a very stupid question but for me it's hard :)
TL;DR: Want to check for proper user input by running my function again, get stuck in weird loop
Thank you for your time and effort!
The code calls userWelcome() recursively, without changing the global variable userInput. The same bad string is processed again, causing the same result, which again calls userWelcome() - for ever (at least until max call depth).
You should read a new string at the beginning of userWelcome, instead of using a global variable. Also, recursion here is an overkill that confuses you. Better use a simple while loop:
while True:
userInput = ....
if ....
do something
return
elif ...
do something else
return # exit the function - breaking out of the loop
else:
print(error message)
# No return here, means the loop will continue to loop
If you want to call the function instead of loop inside, you can instead make the function return success (True) vs. failure (False), and loop that in the caller:
while not userWelcome(inputString):
inputString = read the string
def userWelcome(inputString):
if inputString == ....:
something
return True # To mark OK
elif inputString == .....:
something else
return True # To mark OK
else:
print an error
return False # To mark failure
Just avoid global variables, it is a bad practice. Pass the value through parameters, as in the code above.

Password check- Python 3

Write a function that checks whether a string is valid password.
Rules:
Must have at least 8 characters
A password must consist of only letters and digits
A password must contain at least 2 digits
Heres what I have so far, what am i doing wrong? thank you
def getPassword():
password = input("Enter password: ")
return password
def validPassword(password):
if len(password) >= 8:
valid = True
if password.alnum():
valid = True
if password.isdigit < 2:
valid = True
else:
return False
def main():
password = validPassword()
if validPassword(password):
print(password, "is valid")
else:
print(password, "is invalid")
main()
This seems like a homework assignment so I'll try and stay from directly answering, but more try to push you in the right direction.
Your first bit of code that will run will be
...
def main():
password = validPassword() # the password we are trying to check
...
Uh oh, validPassword(password) takes an argument and doesn't get a password, maybe you meant getPassword()
Lets go through the logic of validPassword(password) Line by line
...
def validPassword(password):
if len(password) >= 8:
valid = True
...
lets check if the length of the string is more than 8 characters, if it is, we initialize the variable valid and set it to True
...
if password.alnum():
valid = True
...
Then regardless of what has happened, we call alnum, ( which I don't think is a function in python, probably meant isalnum. ) to check if all the characters in the password are numbers.
If it is we initialize the variable valid and set it to True.
You may say, but I already initialized it, well not really, in python there is scope.
...
if password.isdigit < 2:
valid = True
...
Then we check if the passwords method isdigt is less than 2, maybe you meant password.isdigit() I am really being meticulous as it is unclear your proficiency in programming or python. But if you meant password.isdigit() < 2 then you are asking if the password is a digit and if yes, is it less than 2.
If it is we initialize the variable valid and set it to True.
...
else:
return False
...
Then if and only if password.isdigit() < 2 is false, we return false.
Here are some pointers:
Learn about control flow in python
When you ask a question here, rather than say, "here is problem, here
is my current code, please help," say, "here is problem, here is my
current code, this is what I expect on line x,y,z and a,b,c is
happening, please help" if we do not know where you are struggling,
how can we help you best
Try and run your code and show us the stacktrace ( if it exists ), there are definitely errors here that would have come up, python happens to have nicer errors that most languages (in my opinion)
Hopefully my line by line explanation has helped you find some of your errors and a better idea of how to continue, if not, feel free to amend your question so that we get a better idea of how to help.
Happy coding.
According to the following reference here for the isdigit() method :
This method returns true if all characters in the string are digits
and there is at least one character, false otherwise.
Which doesn't hold for your case
A password must contain at least 2 digits
The method will only let you know if the given string is a digit, not how many digits are in a string. To achieve that you will need to play around a bit.
You may use the following
if sum(character.isdigit() for character in password) >= 2:
Furthermore, your code has a small mistake as you will never return back True. Here is a possible fix:
def CountDigitsFor(password):
return sum(character.isdigit() for character in password)
def validPassword(password):
if len(password) >= 8 and password.isalnum() and CountDigitsFor(password) >= 2:
return True
return False
Additioanly, in your main you have a small typo when getting the password from the user
password = validPassword()
Should be
password = getPassword()
Therefore here is a complete code
def getPassword():
return input("Enter password: ")
def CountDigitsFor(password):
return sum(character.isdigit() for character in password)
def validPassword(password):
if len(password) >= 8 and password.isalnum() and CountDigitsFor(password) >= 2:
return True
return False
def main():
password = getPassword()
if validPassword(password):
print(password + " is valid")
else:
print(password + " is invalid")
main()

Python: while (True != True) loop

I started learning to code this week so I'm playing around with small programs that I'm creating to try to get a better understanding of how it work.
One of the programs I made is a Pig Latin translator that loops until the user exits. The program works but the logic isn't making any sense to me.
pyg = "ay" #Pig Latin words end with ay.
def translate(): #Creating a function.
original = input("Enter a word: ").lower() #Ask for input then convert to lower.
if len(original) > 0 and original.isalpha() : #isalpha() verifies only abc's and more than one letter.
first = original[0] #Assigns the first letter of the string to first.
latin = original[1:] + first + pyg #Adds original starting at 2nd letter with first and pyg.
print(latin)
else:
print("You did not enter a valid word, please try again.")
translate() #If you did not enter valid word, then call function again until you do.
translate() #Don't forget to actually call the function after you define it.
#Set run to False.
#Can be set to True if while (run != True) is set to while (run == True).
run = False
#Defining cont(). Ask for imput and error handling.
def cont():
loop = input("Would you like to convert another word? (y/n): ").lower()
if loop == "y" :
run = True
elif loop == "n" :
run = False
print("Thank you for using this program, have a nice day!")
exit()
else :
print("You did not enter a valid response, please try again.")
cont()
cont()
#Infinite loop as long as run is not equal to True.
while (run != True) :
translate()
cont()
My question is, why does this program work? I set run to False and I set the loop to run as long as run != True. No problem there, however when I defined cont(), I set run to take on the value True if the user inputs "y". True != True should be False (if I understand correctly) and the loop should end, but instead it is working as I wanted it to.
Is this a coding mistake that I've made or am I just thinking about this the wrong way? Thank you in advance.
Edit: Thank you very much to everyone that answered. I hadn't learned about local and global variables yet.
To expand on what others have already stated, run on these lines
if loop == "y" :
run = True
elif loop == "n" :
run = False
are not referring to the same run defined by
#Can be set to True if while (run != True) is set to while (run == True).
run = False
run in the cont function is a local variable to your function, not the globaly defined run.
There are a couple (at least) ways to fix this. The preferred (imo) way to do it is have cont return a new value to be assigned to run. That would look like
#Defining cont(). Ask for imput and error handling.
def cont(_run):
loop = input("Would you like to convert another word? (y/n): ").lower()
if loop == "y" :
return _run
elif loop == "n" :
return not _run
else :
print("You did not enter a valid response, please try again.")
return cont(_run)
...
#Infinite loop as long as run is not equal to True.
while (run != True) :
translate()
run = cont(run)
The other (less preferred) way would be to use the global run variable inside of your cont function. This is achieved using the global keyword.
That would look like this:
#Defining cont(). Ask for imput and error handling.
def cont():
global run
loop = input("Would you like to convert another word? (y/n): ").lower()
if loop == "y" :
run = True
elif loop == "n" :
run = False
print("Thank you for using this program, have a nice day!")
exit()
else :
print("You did not enter a valid response, please try again.")
cont()
** Couple side notes
In my first example I return _run when the value is y and not _run when the value is n. This allows you to change you initial run value to be True, and change the while condition without having to change the cont function itself.
You don't need to actually change the run value at all if you use the global and the user enters n since you exit before the function returns.
You might be better off changing your if conditional checks to
if loop in ("yes", "y"):
if loop in ("no", "n"):
since lots of people don't read full instructions :)
The run inside the cont function is a local variable. Changing its value has no effect on the global variable that the while loop refers to.
I think this is probably because of the scope of your run variable; because you're not returning run from your cont function. I believe what your != True check sees is always going to be False outside of that function, though obviously you can successfully end the program within the function.
The problem is that the run variable defined in cont() is not the same as the run variable defined in the global scope. (If you aren't sure what I mean by that you might want to look at https://docs.python.org/3.4/tutorial/classes.html#python-scopes-and-namespaces. Perhaps a better approach for your code would be to have cont() return True or False. It is also more intuitive and readable to use True for when you want to continue. Here's how I would rewrite it.
pyg = "ay" #Pig Latin words end with ay.
def translate(): #Creating a function.
original = input("Enter a word: ").lower() #Ask for input then convert to lower.
if len(original) > 0 and original.isalpha() : #isalpha() verifies only abc's and more than one letter.
first = original[0] #Assigns the first letter of the string to first.
latin = original[1:] + first + pyg #Adds original starting at 2nd letter with first and pyg.
print(latin)
else:
print("You did not enter a valid word, please try again.")
translate() #If you did not enter valid word, then call function again until you do.
#Defining cont(). Ask for imput and error handling.
def cont():
while True:
loop = input("Would you like to convert another word? (y/n): ").lower()
if loop == "y":
return True
elif loop == "n":
print("Thank you for using this program, have a nice day!")
return False
else :
print("You did not enter a valid response, please try again.")
translate()
while cont():
translate()

Why does my While loop Exit?

My comments illustrate my line of reasoning but clearly I've got something wrong. My code just jumps straight to "Your total debt is..."
# Dictionary of Bills
expenses = {'mortgage':[], 'personal':[], 'power':[], 'insurance':[], 'water':[], 'food':[], 'savings':[], 'fuel':[], 'phone':[], 'internet':[], 'credit':[], 'emergencies':[]}
totalDebt = 0
switch = "A"
while switch == switch.isalpha(): # Condition is true, switch is a letter
for each in expenses: # Iterates through each bill
debt = input("%s: "%each) # User input
if debt.isdigit(): # checks to make sure they only enter numbers
debt = int(debt) # Converts debt to its integer value
totalDebt = totalDebt + debt # adds debt to keep a running total.
else: # User entered something other than a number
print("Only enter digits!")
print("Your total Debt is: $%i" %totalDebt)
input("Press Enter to continue: ")
print("What is this fortnights Income?")
Your condition doesn't make any sense here:
while switch == switch.isalpha(): # Condition is true, switch is a letter
switch.isalpha() returns either True or False. switch itself will not be equal to either of those two values, so the whole expression is always going to be False. Remove the equality test:
while switch.isalpha(): # Condition is true, switch is a letter
Note that your code never actually changes switch, so now your loop is going to continue forever.
The While is False
>>> switch
'A'
>>> switch.isalpha()
True
>>> switch == switch.isalpha()
False
You must use switch.isalpha() allown

Categories

Resources