I'm creating a simple program to take in time and distance to then state the speed, but I want to do this with classes to learn about oop in python. I'm not figuring out how to set the loop to keep going until the user decides to not go again.
y=True
while y:
class Timer:
def __init__(self,speed):
self.speed=speed
def log(self):
print(mph)
again=input('Go again? y or n: ')
if again=='y':
y=True
else:
print('Thank you')
y=False
m=float(input('Enter the minutes: '))
s=float(input('Enter the seconds: '))
d=float(input('Enter distance: '))
x=(m*60) s
x_tot=(x/3600)
mph=d/x_tot
t=Timer(mph)
t.log()
CodePudding user response:
You need following code:
y=True
while y:
class Timer:
def __init__(self,speed):
self.speed=speed
def log(self):
print(mph)
global y
again=input('Go again? y or n: ')
if again=='y':
y=True
else:
print('Thank you')
y=False
if y:
m=float(input('Enter the minutes: '))
s=float(input('Enter the seconds: '))
d=float(input('Enter distance: '))
x=(m*60) s
x_tot=(x/3600)
mph=d/x_tot
t=Timer(mph)
t.log()
else:
break
The y
variabel inside log
function should be global else it won't change global y
referred inside if-else. We need if-else with y
so that we can break out of loop if user chooses n
. The t=Timer(mph)
has to be inside while
loop because class is not known outside the loop. Same applies for t.log
function call.
CodePudding user response:
Honestly to make your code easier to debug and track where changes are occuring, you should pull the class out of the loop and then reference it inside the loop when you need to use it.
In the init, I would pull out the assignment of the speed variable and just initialize it as none
.
def __init__(self):
self.speed = None
Then you can add a separate private setter function to set the speed with user input and do error checking around it. Note, I have set the program to exit with a 0 code if the user inputs something wrong, but you can easily make another loop here that will wait until the user finally does input valid values for all the inputs. The __
double underscore in front of the function name makes it private to the class.
def __set_mph(self):
try:
m = float(input('Enter the minutes: '))
s = float(input('Enter the seconds: '))
d = float(input('Enter distance: '))
x = (m * 60) s
x_tot = (x / 3600)
self.mph = d / x_tot
except (ValueError, ArithmeticError) as e:
print(f'Invalid user input: {e}')
exit(0)
except Exception as e:
print(f'Unexpected error: {e}')
exit(0)
Now you can update the log function to not even worry about the y variable by changing it to this:
def log(self):
self.__set_mph()
print(mph)
again = input('Go again? y or n: ')
if again == 'y':
return True
else:
print('Thank you')
return False
Now we just initialize the class before the loop and clean it up to be make it more manageable.
t = Timer()
while True:
if not t.log():
break
Final Code:
class Timer:
def __init__(self):
self.speed = None
self.mph = None
def __set_mph(self):
try:
m = float(input('Enter the minutes: '))
s = float(input('Enter the seconds: '))
d = float(input('Enter distance: '))
x = (m * 60) s
x_tot = (x / 3600)
self.mph = d / x_tot
except (ValueError, ArithmeticError) as e:
print(f'Invalid user input: {e}')
exit(0)
except Exception as e:
print(f'Unexpected error: {e}')
exit(0)
def log(self):
self.__set_mph()
print(self.mph)
again = input('Go again? y or n: ')
if again == 'y':
return True
else:
print('Thank you')
return False
t = Timer()
while True:
if not t.log():
break
CodePudding user response:
OOP is all about modeling your real world objects into programmatic objects that maintain the features and functionality of the real world object to its programatic counterpart's attributes and features, respectively.
Also, those objects should be separated on its own. Creating and calling a class from within a while loop is pretty bad practice. I would encourage you to separate the code based on its purpose. for example, I would have a file called timer.py
to handle the Object that matches the timer like so:
# The timer class
class Timer:
def calculate_speed(self, minutes, seconds, distance):
hours = (minutes * 60) seconds
tot_time = (hours / 3600)
return distance / tot_time
def get_speed(self):
minutes = float(input('Enter the minutes: '))
seconds = float(input('Enter the seconds: '))
distance = float(input('Enter distance: '))
return self.calculate_speed(minutes, seconds, distance)
Then in your main file:
from timer import Timer
timer = Timer()
while True:
user_response = input('Go again? y or n: ').lower()
if user_response == 'n':
break
elif user_response == 'y':
speed = timer.get_speed()
print(f'Your speed is {speed}')
else:
print('Not a valid response')
This makes it easier on the backend too. In other words, if you have an error that relates to the calculations, you know where to start looking.