Home > OS >  Trying to create a class which goes in a loop once the class and def is called
Trying to create a class which goes in a loop once the class and def is called

Time:10-13

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.

  • Related