This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 5 years ago.
I am trying to write a program that finds happy numbers:
more info here.
This is not a school assignment, but I'm just trying to practice my Python 2.7.
Basically, recursion is a vital part of this because I have to keep squaring every digit.
In my code, I use recursion to keep running it, I have a base case, and it works, but for some reason, even though I call the function, no recursion occurs.
It just returns the digits squares for the first number, which is a bug test, and it returns None, then it stops running.
What's the problem?
num = raw_input('Pick a positive integer that you want to check for a happy number')
def happyn(number,second,third,fourth):
if len(number) == 2:
go = int(number[0])**2 + int(number[1])**2
elif len(number) == 3:
go = int(number[0])**2 + int(number[1])**2 + int(number[2])**2
elif len(number) == 4:
go = int(number[0])**2 + int(number[1])**2 + int(number[2])**2 + int(number[2]**2)
if len(number) == 1 and int(number) == 1 or int(number) == 7:
return True
elif len(number) == 1:
return False
else:
print go
go = str(go)
go1 = go[0]
print go1
if len(go) == 1:
go1 = go[0]
happyn(go1,0,0,0)
elif len(go) == 2:
go1 = go[0]
go2 = go[1]
happyn(go1,go2,0,0)
elif len(go) == 3:
go1 = go[0]
go2 = go[1]
go3 = go[2]
happyn(go1,go2,go3,0)
elif len(go) == 4:
go1 = go[0]
go2 = go[1]
go3 = go[2]
go4 = go[4]
happyn(go1,go2,go3,go4)
print happyn(num,0,0,0)
All the possible execution branches must return something, otherwise the recursion won't work. For example, this is wrong:
happyn(go1,0,0,0)
If nothing is explicitly returned, the function will return None. Therefore, the correct way is:
return happyn(go1,0,0,0)
The same goes for all the other exit points in your function.
You are not returning the result of your recursive calls, ie return happyn(go1, 0, 0, 0). In Python, any function that ends without a return statement implicitly returns None.
This is not really a good place to use recursion; a simple while loop would suit better.
def sum_sq(i):
total = 0
while i:
total += (i % 10) ** 2
i //= 10
return total
def is_happy(i):
while i >= 10:
i = sum_sq(i)
return i in (1, 7)
def main():
i = int(raw_input("Please enter a positive integer: "))
if is_happy(i):
print("{} is a happy number.".format(i))
else:
print("{} is an unhappy number.".format(i))
if __name__=="__main__":
main()
Related
(I'm a beginner in Python, just so you know)
What I'm trying to do: I want to keep count of how many times a user choose a wrong option and if it exceeds a number of times, he fails.
My approach was to store the count in a variable within a function and check with if/else statement if the number of times is exceeded.
Part of the code:
choice = int(input("> "))
if choice == 1:
print("This is the wrong hall.")
increment()
elif choice == 2:
print("This is the wrong hall.")
increment()
elif choice == 3:
hall_passage()
else:
end("You failed")
COUNT = 0
def increment():
global COUNT
COUNT += 1
increment()
print(COUNT)
The increment part is from this thread and read using global scope is not a good practice.
The part I don't really understand is how you store count in a variable and it remembers the last value every time the function runs.
What is the best way to do this?
maybe something like this...
class Counter():
def __init__(self):
self.counter = 0
def increment(self):
self.counter += 1
def reset(self):
self.counter = 0
def get_value(self):
return self.counter
mc = Counter()
while mc.get_value() < 3:
v = int(input('a number: '))
if v == 1:
print('You won!')
mc.counter = 3
else:
print('Wrong guess, guess again...')
if mc.counter == 2:
print('Last guess...')
mc.increment()
Adapting this answer you could utilize the functions own __dict__. Note: if you didn't come across the # syntax yet search for "python", "decorator":
import functools as ft
def show_me(f):
#ft.wraps(f)
def wrapper(*args, **kwds):
return f(f, *args, **kwds)
return wrapper
#show_me
def f(me, x):
if x < 0:
try:
me.count += 1
except AttributeError:
me.count = 1
print(me.count, 'failures')
f(0)
f(-1)
f(1)
f(-2)
Output:
1 failures
2 failures
What do you think about this solution?
If you put here while loop you will forced on user to put correct answer.
Also i placed between if/elif/else statements input function.
count - That variable is counting wrong options
choice = int(input("> "))
count =0
while choice !=3:
if choice == 1:
print("This is the wrong hall.")
count += 1
choice = int(input("> ")) # Also i place in the if/elif/else statements input function
elif choice == 2:
print("This is the wrong hall.")
count +=1
choice = int(input("> "))
elif choice == 3:
hall_passage()
else:
end("You failed")
count += 1
choice = int(input("> "))
print(count)
I have a binary search that searches a list from a user given input of an email. I get no errors and I get no output from it. I can't see where its going wrong?
def BubbleSort(logindata):
NoSwaps = 1
N = len(logindata)
logindata = list(logindata)
while NoSwaps == 1:
Count = 1
NoSwaps = 0
for Count in range(N-1):
if logindata[Count] > logindata[Count+1]:
temp = logindata[Count]
logindata[Count] = logindata[Count+1]
logindata[Count+1]=temp
NoSwaps=1
return tuple(logindata)
def BinarySearch(logindata,ItemSought):
First=0
Last=len(logindata)-1
ItemFound = False
SearchFailed = False
while ItemFound == False or SearchFailed == False:
Midpoint = (First + Last) // 2
if logindata[Midpoint] == ItemSought:
print("Item Found")
ItemFound = True
print("Item Found")
break
elif logindata[Midpoint][0] > ItemSought:
Last = Midpoint - 1
else:
First = Midpoint + 1
if __name__ == "__main__":
logindata=["tom#gmail.com","Password1"],["harry#gmail.com","Password2"],["jake#gmail.com","Password3"]
logindata=BubbleSort(logindata)
print(logindata)
ItemSought=input("Enter username")
BinarySearch(logindata,ItemSought)
In
if logindata[Midpoint] == ItemSought:
you compare list with a string. So I think you need
if logindata[Midpoint][0] == ItemSought:
You never terminate the search. If the item isn't in the list, you get to a stable midpoint and loop infinitely. If you do find the item, you loop infinitely on that (see Yehven's answer).
I traced it with the additions you see here:
SearchFailed = False
iter = 0
while iter < 10 and (ItemFound == False or SearchFailed == False):
iter += 1
Midpoint = (First + Last) // 2
print (First, Midpoint, Last, ItemSought)
if logindata[Midpoint] == ItemSought:
Note that you don't ever change SearchFailed. For instance, when I search for "harry", the loop hits a stable infinite point at (0, -1, -2) for First, Middle, Last.
Is that enough of a hint to let you fix it yourself?
I'm a beginner Python learner and I'm currently working on Luhn Algorithm to check credit card validation. I wrote most of the code, but I'm stuck with 2 errors I get 1st one is num is referenced before assignment. 2nd one I'm getting is object of type '_io.TextIOWrapper' has no len(). Further help/ guidance will be greatly appreciated.
These are the steps for Luhn Algorithm (Mod10 Check)
Double every second digit from right to left. If this “doubling” results in a two-digit number, add the two-digit
number to get a single digit.
Now add all single digit numbers from step 1.
Add all digits in the odd places from right to left in the credit card number.
Sum the results from steps 2 & 3.
If the result from step 4 is divisible by 10, the card number is valid; otherwise, it is invalid.
Here's what my output is supposed to be
Card Number Valid / Invalid
--------------------------------------
3710293 Invalid
5190990281925290 Invalid
3716820019271998 Valid
37168200192719989 Invalid
8102966371298364 Invalid
6823119834248189 Valid
And here is the code.
def checkSecondDigits(num):
length = len(num)
sum = 0
for i in range(length-2,-1,-2):
number = eval(num[i])
number = number * 2
if number > 9:
strNumber = str(number)
number = eval(strNumber[0]) + eval(strNumber[1])
sum += number
return sum
def odd_digits(num):
length = len(num)
sumOdd = 0
for i in range(length-1,-1,-2):
num += eval(num[i])
return sumOdd
def c_length(num):
length = len(num)
if num >= 13 and num <= 16:
if num [0] == "4" or num [0] == "5" or num [0] == "6" or (num [0] == "3" and num [1] == "7"):
return True
else:
return False
def main():
filename = input("What is the name of your input file? ")
infile= open(filename,"r")
cc = (infile.readline().strip())
print(format("Card Number", "20s"), ("Valid / Invalid"))
print("------------------------------------")
while cc!= "EXIT":
even = checkSecondDigits(num)
odd = odd_digits(num)
c_len = c_length(num)
tot = even + odd
if c_len == True and tot % 10 == 0:
print(format(cc, "20s"), format("Valid", "20s"))
else:
print(format(cc, "20s"), format("Invalid", "20s"))
num = (infile.readline().strip())
main()
You just forgot to initialize num
def main():
filename = input("What is the name of your input file? ")
infile= open(filename,"r")
# initialize num here
num = cc = (infile.readline().strip())
print(format("Card Number", "20s"), ("Valid / Invalid"))
print("------------------------------------")
while cc!= "EXIT":
even = checkSecondDigits(num)
odd = odd_digits(num)
c_len = c_length(num)
tot = even + odd
if c_len == True and tot % 10 == 0:
print(format(cc, "20s"), format("Valid", "20s"))
else:
print(format(cc, "20s"), format("Invalid", "20s"))
num = cc = (infile.readline().strip())
First, maybe you should remove the extra characters:
def format_card(card_num):
"""
Formats card numbers to remove any spaces, unnecessary characters, etc
Input: Card number, integer or string
Output: Correctly formatted card number, string
"""
import re
card_num = str(card_num)
# Regex to remove any nondigit characters
return re.sub(r"\D", "", card_num)
After check if credit card is valid using the Luhn algorithm:
def validate_card(formated_card_num):
"""
Input: Card number, integer or string
Output: Valid?, boolean
"""
double = 0
total = 0
digits = str(card_num)
for i in range(len(digits) - 1, -1, -1):
for c in str((double + 1) * int(digits[i])):
total += int(c)
double = (double + 1) % 2
return (total % 10) == 0
This is a very simpler version of code it is based on lunh's algorithm
def validator(n):
validatelist=[]
for i in n:
validatelist.append(int(i))
for i in range(0,len(n),2):
validatelist[i] = validatelist[i]*2
if validatelist[i] >= 10:
validatelist[i] = validatelist[i]//10 + validatelist[i]%10
if sum(validatelist)%10 == 0:
print('This a valid credit card')
else:
print('This is not valid credit card')
def cardnumber():
result=''
while True:
try:
result = input('Please enter the 16 digit credit card number : ')
if not (len(result) == 16) or not type(int(result) == int) :
raise Exception
except Exception:
print('That is not a proper credit card number. \nMake sure you are entering digits not characters and all the 16 digits.')
continue
else:
break
return result
def goagain():
return input('Do you want to check again? (Yes/No) : ').lower()[0] == 'y'
def main():
while True:
result = cardnumber()
validator(result)
if not goagain():
break
if __name__ == '__main__':
main()
Old thread but the answer concerns me... and the real issue wasn't identified.
Actually, the error is that you have used the identifier (num) for the parameter when defining checkSecondDigits as the identifier/name of the argument when calling the function in the mainline. The function should be called in main() by
even = checkSecondDigits(cc) so the value in cc (which is the argument) is passed into num (as the parameter) for use within the function.
The same rookie error is made with odd_digits and cc_length.
This question (and the initially suggested answer) demonstrates a fundamental mis-understanding of passing arguments to parameters...
The suggested 'declaring' of num just hides this error/misunderstanding and also obfuscates the local and global scopes of num (which should only be local) and cc (which is global) so whilst the suggestion works in this case, it works for the wrong reason and is poor style and bad programming.
Further,
num should not appear anywhere in main() as it should be local to (only appear inside of) the functions called...
The last line in this code should be the same as the first, but the last line incorrectly assigns the data to num instead of cc
cc = (infile.readline().strip())
print(format("Card Number", "20s"), ("Valid / Invalid"))
print("------------------------------------")
while cc!= "EXIT":
even = checkSecondDigits(num)
odd = odd_digits(num)
c_len = c_length(num)
tot = even + odd
if c_len == True and tot % 10 == 0:
print(format(cc, "20s"), format("Valid", "20s"))
else:
print(format(cc, "20s"), format("Invalid", "20s"))
num = (infile.readline().strip())
you can use my code for card validation it is 100% dynamic because of the card structure is stored in CSV file, so it is easy to update here is the code on GitHub profile, python file link, code explanation file link and CSV for datafile link
python code:
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 10 20:55:30 2019
#author: Preyash2047#gmail.com
"""
import csv
import numpy as np
#csv file imported and storf in reader
reader = csv.DictReader(open("card_data.csv"))
#input card number
card_number = input("Enter the card No: ")
#global variable declaration
min_digits=0
max_digits=0
card_number_list = list(card_number)
card_number_list_reverse=card_number_list[::-1]
card_number_length=len(card_number_list)
first_digit = int(card_number_list[0])
#global variable for final output
card_provider_list_number = 0
result_found = False
card_number_digits = 0
mit_name=""
#list
start=[]
end=[]
name=[]
c_d=[]
number_length=[]
min_max_digits_list=[]
#append the list from csv
for raw in reader:
start.append(raw['start'])
end.append(raw['end'])
name.append(raw['name'])
c_d.append(raw['c_d'])
number_length.append(raw['number_length'])
#initialize the value of min_digits & max_digits
def min_max_digits():
global min_digits
global max_digits
for i in range(len(start)):
available_length=number_length[i].split(',')
for j in range(len(available_length)):
min_max_digits_list.append(available_length[j])
min_max_digits_array = np.array(min_max_digits_list)
np.unique(min_max_digits_array)
min_digits=int(min(min_max_digits_array))
max_digits=int(max(min_max_digits_array))
#list to int
def list_to_int(noofdigits):
str1 = ""
return int(str1.join(noofdigits))
#card validation
def iin_identifier():
first_six_digit = list_to_int(card_number_list[0:6])
for i in range(len(start)):
if(first_six_digit >= int(start[i]) and first_six_digit <= int(end[i])):
available_length=number_length[i].split(',')
for j in range(len(available_length)):
if(card_number_length == int(available_length[j])):
global card_provider_list_number
card_provider_list_number = i
global card_number_digits
card_number_digits = available_length[j]
global result_found
result_found = True
#Major Industry Identifier (MII) identification
def mit_identifier():
global first_digit
global mit_name
switcher = {
1: "Airlines",
2: "Airlines",
3: "Travel and Entertainment",
4: "Banking and Financial Services",
5: "Banking and Financial Services",
6: "Merchandising and Banking",
7: "Petroleum",
8: "Health care, Telecommunications",
9: "National Assignment"
}
mit_name=switcher.get(first_digit, "MIT Identifier Not Found")
#Luhn Algorithm or modulo-10 Algorithm
def luhn_algorithm():
for i in range(card_number_length):
if(i%2!=0 and i!=0):
card_number_list_reverse[i]=int(card_number_list_reverse[i])*2
#print(str(i)+" "+ str(card_number_list_reverse[i]))
if(len(str(card_number_list_reverse[i]))==2):
even_number_2=list(str(card_number_list_reverse[i]))
card_number_list_reverse[i] = int(even_number_2[0])+int(even_number_2[1])
#print("\tsubsum "+str(i)+" "+str(card_number_list_reverse[i]))
else:
card_number_list_reverse[i]=int(card_number_list_reverse[i])
division_int = int(sum(card_number_list_reverse)/10)
division_float=sum(card_number_list_reverse)/10
if(division_int-division_float==0):
return True
#initial level number length validation
def card_number_validation():
min_max_digits()
if(card_number_length>= min_digits and card_number_length <= max_digits and first_digit != 0):
iin_identifier()
mit_identifier()
if(result_found and luhn_algorithm()):
print("\nEntered Details are Correct\n")
print("\nHere are the some details we know about you card")
print("\nNo: "+card_number)
print("\nIssuing Network: "+name[card_provider_list_number])
print("\nType: "+c_d[card_provider_list_number]+" Card")
print("\nCategory of the entity which issued the Card: "+mit_name)
else:
print("\nCard Number is Invalid\nPlease renter the number!\n")
else:
print("\nCard Number is Invalid\n")
#method called to run program
card_number_validation()
n = input("Enter 16-digit Credit Card Number:")
lst = []
for i in range(16):
lst.append(n[i])
# print(lst)
# list1 = n.split()
# print(list1)
def validate_credit_card():
global lst
if len(lst) == 16:
for i in range(0, len(lst)):
lst[i] = int(lst[i])
# print(lst)
last = lst[15]
first = lst[:15]
# print(first)
# print(last)
first = first[::-1]
# print(first)
for i in range(len(first)):
if i % 2 == 0:
first[i] = first[i] * 2
if first[i] > 9:
first[i] -= 9
sum_all = sum(first)
# print(first)
# print(sum_all)
t1 = sum_all % 10
t2 = t1 + last
if t2 % 10 is 0:
print("Valid Credit Card")
else:
print("Invalid Credit Card!")
else:
print("Credit Card number limit Exceeded!!!!")
exit()
if __name__ == "__main__":
validate_credit_card()
Like using this to validate that an input is only alpha-numeric:
while True:
str = input('')
if str.isalnum():
break
else:
print("Please include only alpha-numeric characters.\n")
This code has worked for all instances that I have tested it in, but is this bad practice?
That's fine. Here is a note, however: you can find out if the while loop exited with a break or without one by using else:
x = 0
while x < 4:
x += 1
else:
print("no break")
# prints no break
If you break, however:
x = 0
while x < 4:
x += 1
if x == 2:
break
else:
print("no break")
# Does not print
you can abstract it further
def verified_input(prompt='',test_condition=lambda x:1,err_message="Please Enter Valid Input"):
while True:
result = input(prompt)
if test_condition(result):
return result
print( err_message )
def verified_alnum(prompt,err_message="Please enter Only alpha numerics"):
return verified_input(prompt,lambda x:x.isalnum(),err_message)
result = verified_alnum("Enter Password:","A password must be only letters and numbers")
this allows you to create any number of test conditions quickly and relatively verbosely
So first, the assignment given was to make the function "compute" solves it and returns the value. If the given sting is not a valid equation, returns "None"
def compute(side):
val=int(side[0])
lastop=0
for i in range(1,len(side)):
if side[i].isdigit():
if lastop=='+':
val+=int(side[i])
elif lastop=='-':
val-=int(side[i])
elif lastop=='x':
val*=int(side[i])
elif lastop=='/':
val/=int(side[i])
else:
lastop=side[i]
return val
So at this point the value would be returned. But if the function is run for ("22-11x4"), it gives 0 not 44. I've turned them into integers and why would they still give me the wrong value?
def evaluate():
val=int(side[0])
lastop=0
for i in range(1,len(side)):
if side[i].true():
print('Congrats')
elif side[i].false():
print('Try again')
And when it gets to this evaluate function, it gives the error of "invalid literal for int() with base 10: '+'" and I am not too sure what this means and how to solve.
def solve():
pass
This function "solve" I was going to get to later after I have fixed the problems in the functions before.
def main():
print("22-11x4 =", compute("22-11x4"),"(expect 44)")
print("+11x4 =", compute("+11x4"),"(expect None)")
print("22-11x4 ?= 7x5+9", evaluate("22-11x4=7x5+9"),"(expect True)")
print("solving 288/24x6=18x13x8 :", solve("288/24x6=18x13x8"))
main()
The compute function you wrote does operation by digit, also you forgot to do one, last operation after for was finished:
2 - 1 - 1 x 4 = 0
this why you got this return from the function
Here is the correct function
def compute(side):
val = 0
buf = 0
lastop = '+'
for i in range(0, len(side)):
if side[i].isdigit():
buf = buf * 10 + int(side[i])
else:
val = op(val, buf, lastop)
lastop = side[i]
buf = 0
val = op(val, buf, lastop)
return val
def op(val, buf, lastop):
if lastop == '+':
val += buf
elif lastop == '-':
val -= buf
elif lastop == 'x':
val *= buf
elif lastop == '/':
val /= buf
return val
Also in your testing string:
print("+11x4 =", compute("+11x4"),"(expect None)")
why do you expect None? it should be 44?
PS. this function could be improved yet, but I had no time to do it. anyway it works.