# Beginner cigarette questioning program

While working through a challenge in the beginning of a book I'm reading. I wanted to make my first program more versatile in its responses while trying to fix any exceptions that it was throwing at me. I'm not really sure how well I've made it and I'm looking for any advice on where I can improve it. Here is the program:


def agelist(r1= 1, r2= 250):
return[item for item in range(r1, r2+1)]
z = agelist()

def agecheck(x):
agelimit = input("I'm sorry, please enter a valid number for your age.")
q = int(agelimit)
if q in z:
paymentmethod2(q)
elif q not in z:
agecheck(q)

def paymentmethod(x):
print("Here is your receipt. Thanks and have a great day!")

def paymentmethod2(x):
payment2 = input("Please enter either a 1 for Cash or 2 for Credit.")
y = int(payment2)
if y == 1:
print("Thanks! Have a nice day!")
elif y == 2:
print("Thanks! Have a nice day!!")
else:
paymentmethod2(y)

def savingspace(x):
x = int(payment)
if x == 1:
paymentmethod(x)
elif x == 2:
paymentmethod(x)
else:
paymentmethod2(x)

while True:
try:
age1 = int(input("I see you'd like to buy some cigarettes. How old are you?"))
except ValueError:
print("Sorry, I didn't understand that.")
continue
else:
break
age = int(age1)

if age in z:
if age < 21:
if age >= 13:
print("You're too young to buy these things!")
print("Go find something else to buy.")
else:
print("This isn't a place for you son.")
print("Come back with your parents next time.")

elif age < 125:
if age <= 40:
print("Sorry for the trouble. Pesky new laws in this county make us have to check.")
payment= input("How'd you like to pay? Press 1 on the numpad for Cash or 2 for Credit.")
savingspace(payment)
else:
print("Those good ol' cowboys amiright hehe, wouldn't be Texas without em!")
payment= input("How'd you like to pay? Press 1 on the numpad for Cash or 2 for Credit.")
savingspace(payment)
else:
print("Out of respect for your ancient being; I will forget what I saw here. Take your cigarettes and go.")

elif age not in z:
agecheck(age)
input()



This is how I tried to fix my errors before I read chocolate's post.

z = range(1, 251) #specifies range of integers that this program will use

def agecheck(x): #function allows age to be corrected to a number in z list. My while loops are cause a bit of a mess, but it works kinda.
while True:
try:
agelimit = input("Voided, please enter a valid number for your age again.")
q = int(agelimit)
if q in z:
paymentmethod2(q)
elif q not in z:
agecheck(q)
except ValueError:
print("Please choose a number below 250.")
continue
else:
break

def paymentmethod(x): #funtion which receives param from savingspace function and prints closing str
print("Here is your receipt. Thanks and have a great day!")

def paymentmethod2(x): #final function is called when an int other than 1 or 2 is passed to savingspace(x)
payment2 = input("Please enter either a 1 for Cash or 2 for Credit.") #requests input to be either 1 or 2
y = int(payment2)
if y == 1:
print("Thanks! Have a nice day!")
elif y == 2:
print("Thanks! Have a nice day!!")
else:
paymentmethod2(y) #if input isnt 1 or 2, calls itself with a different variable to fix
#for some reason entering a non integer at this point bounces it back to the while loop where payment is defined??
def savingspace(x): #function I used to save space in program and sort the input provided
x = int(payment)
if x == 1:
paymentmethod(x)
elif x == 2:
paymentmethod(x) #if payment is 1 or 2, calls paymentmethod(x) function
else:
paymentmethod2(x) #if its any other number, calls paymentmethod2(x) to fix input

while True: #Beginning of program: asks & defines age and loops if input is not an integer
try:
age = int(input("I see you'd like to buy some cigarettes. How old are you?"))
except ValueError:
print("Sorry, I didn't understand that.")
continue
else:
break

#takes age and sorts it to print str based on user's input
if age in z: #checks if user's age is valid based on number list defined by function z
if age < 21:
if age >= 13:
print("You're too young to buy these things!")
print("Go find something else to buy.")
else:
print("This isn't a place for you son.")
print("Come back with your parents next time.")

elif age < 125:
if age <= 40:
print("Sorry for the trouble. Pesky new laws in this county make us have to check.")
while True: #loop handles ValueError exception when a non integer is input
try:
payment= input("How'd you like to pay? Press 1 on the numpad for Cash or 2 for Credit.")
#sets payment pref as variable
savingspace(payment)#passes payment pref variable to function which sorts the payment var
except ValueError:
print("Sorry only 1 or 2 is allowed to be input.")
continue
else:
break
else:
print("Those good ol' cowboys amiright hehe, wouldn't be Texas without em!")
while True: #same as above
try:
payment= input("How'd you like to pay? Press 1 on the numpad for Cash or 2 for Credit.")
savingspace(payment)
except ValueError:
print("Sorry only 1 or 2 is allowed to be input.")
continue
else:
break
else:
print("Out of respect for your ancient being; I will forget what I saw here. Take your cigarettes and go.")

elif age not in z: #if the number provided isn't valid in list; calls function agecheck to ensure a valid input
agecheck(age)
input() #so the program doesnt just shut off after the last response

• Provide more context, what does the program do? Dec 2 '20 at 0:46
• Thanks, by that do you mean that I should add comments on which parts do what and how it all flows together? Dec 2 '20 at 1:14
• Hi parapuffer. You should add the problem your code solves in your post (the context), otherwise it's hard for reviewers to see exactly what you want your code to do Dec 2 '20 at 14:18

1. Instead of using range to define a list of numbers, use the <, > and = operators to save efficiency.

2. In many of your functions, you've given then an argument that the function doesn't use at all, which only wastes efficiency.

if y == 1:
print("Thanks! Have a nice day!")
elif y == 2:
print("Thanks! Have a nice day!")


You can do:

if y in [1, 2]:
print("Thanks! Have a nice day!")


and same goes for the others.

1. Instead of defining age1, and then defining another variable, age, to store the exact same value, and never using age1 again, simply use the age1 (which I renamed to age).

2. You can define a function that will take care of retrieving a valid age from the user.

Here is the implementation:

def get_age():
while True:
try:
age = int(input("How old are you? "))
except ValueError:
print("Sorry, I didn't understand that. ")
continue
if 250 < age or age < 1:
continue
return age

def paymentmethod():
print("Here is your receipt. Thanks and have a great day!")

def paymentmethod2():
print("Thanks! Have a nice day!!")

def savingspace(x):
if x == '1':
paymentmethod()
else:
paymentmethod2()

print("I see you'd like to buy some cigarettes.")
age = get_age()
if age < 13:
print("This isn't a place for you son.")
print("Come back with your parents next time.")
elif age < 21:
print("You're too young to buy these things!")
print("Go find something else to buy.")
elif age < 125:
if age < 40:
print("Sorry for the trouble. Pesky new laws in this county make us have to check.")
else:
print("Those good ol' cowboys amiright hehe, wouldn't be Texas without em!")
while True:
payment = input("How'd you like to pay? Press 1 on the numpad for Cash or 2 for Credit. ")
if payment in ['1', '2']:
savingspace(payment)
break
else:
print("Out of respect for your ancient being; I will forget what I saw here. Take your cigarettes and go.")
input()
$$$$

• I prefer if not 1 <= age <= 250: over if 250 < age or age < 1:. Dec 2 '20 at 5:21
• Wow your version makes much more sense than mine and fixes the issues I was having. I didn't realize that I could shorten the while loop you used for payment like that. The fix I tried ended up looping back in on itself whenever a function after it had a wrong input. Thanks a lot Dec 2 '20 at 5:28
• Would y in (1, 2) be even more idiomatic than y in [1, 2]? Dec 2 '20 at 6:15
• x in range(0, 10) isn't much slower than 0 <= x < 10. x in range(0, 20000000000) is still a constant-time operation. So long as this isn't happening in a tight loop, speed shouldn't be a concern. (Clarity might be, though, so I agree with that suggestion – just not the rationale.) Edit: The original answer was building a list, from a range, so you are right; I'm leaving this comment in the hopes it might be useful to others. Dec 2 '20 at 7:34
• @wizzwizz4 You're wrong. What I provided is 10 times faster than range. Of course, human may not be able to feel the difference at all, but using the time.perf_counter function show the difference clearly. Dec 2 '20 at 12:56

I'll add the rest of my comments in when I have time, but here's some stuff:

You can replace...

def agelist(r1= 1, r2= 250):
return[item for item in range(r1, r2+1)]
z = agelist()


...with:

z = range(1, 251)

• Thanks, I'm not too knowledgeable yet on all of the built in functions so I appreciate the help. Dec 2 '20 at 1:15
• No, it's z = range(1, 251)`. Dec 2 '20 at 4:56
• @Chocolate -- Whoops, you're right. Dec 2 '20 at 15:08