I am writing a "clean" method for a "Time" class. The clean method would take a Time object and would make sure that the number of seconds and minutes is between 0 and 59. I am running into an error with recursion. Here is what I have so far:
def clean(self):
'''Adjust Time object so that the number of seconds and minutes
is between 0 and 59'''
if self.S < 60:
self.S
else:
self.M = int(self.S/60)+self.M
self.S = self.S%60
if self.M < 60:
self.M
else:
self.H = int(self.M/60)+ self.H
self.M = self.M%60
if isinstance(self.H,float) == True:
self.S = self.H * 3600
self.clean()
else:
self.H
return self.__str__()
In your code:
if isinstance(self.H,float) == True:
self.S = self.H * 3600
self.clean()
else:
You don't change self.H if this is True, so it will always be true. I'm guessing you want to set self.H = 0 or something like that (since you converted it all to seconds).
Also, in your if statements, having 'self.S' doesn't actually do anything, so you should write:
if self.S < 60:
self.S
else:
self.M = int(self.S/60)+self.M
self.S = self.S%60
as
if self.S >= 60:
self.M = int(self.S/60)+self.M
self.S = self.S%60
Also, in your recursive check, you destroy your previous value of self.S, did you mean to add that?
EDIT:
You don't specify in your question, but from your code it looks like you're assuming the time values (S, M, H) are valid and you're just shifting the quantities around to get the same total time with S < 60 and M < 60. If this is the case, then you can easily eliminate the recursion by converting everything to seconds at the beginning and then go through your S and M steps:
self.S = self.H * 3600 + self.M * 60 + self.S
self.M = int(self.S / 60)
self.H = int(self.M / 60) # or = int(self.S / 3600)
self.M = self.M % 60
self.S = self.S % 60
It looks like the only place where recursion happens is here:
if isinstance(self.H,float) == True:
self.S = self.H * 3600
self.clean()
If you make self.H not a float then it won't repeat:
if isinstance(self.H,float) == True:
self.S = self.H * 3600
self.H = int(self.H) # add this line
self.clean()
Better yet, adjust the values at the top so you don't need recursion:
# move this to the first lines of your method
if isinstance(self.H,float) == True:
self.S = self.H * 3600
Related
Im trying to subtract with prefixes as objects.
Here is my code
class Prefix:
def __init__(self, m=0, cm=0):
self.m = m
self.cm = cm
def __sub__(self, other):
centim = self.cm - other.cm
meter = (self.m - other.m) - abs(centim/100)
if meter < 1:
centim = m*100
meter = 0
return Prefix(meter, cm)
Im trying to subtract in a way which creates a negative centimeter value and take 1m from the meter object such that this is fulfilled
Prefix(2, 20) - Prefix(1, 30) == Prefix(0, 90)
First, keep in mind that for a given length, everything to the right of the hundreds place goes into cm, and everything at it or to its left gets divided by 100, and then goes into m.
Given this, we can recast the problem as converting both Prefix objects into their full lengths, performing calculations there, and then creating a new Prefix from the result:
class Prefix:
def __init__(self, m=0, cm=0):
self.m = m
self.cm = cm
def __sub__(self, other):
self_length = self.m * 100 + self.cm
other_length = other.m * 100 + other.cm
result_length = self_length - other_length
result_m, result_cm = divmod(result_length, 100)
return Prefix(result_m, result_cm)
result = Prefix(2, 20) - Prefix(1, 30)
print(result.m, result.cm)
Output:
0 90
Since we've come this far, we might as well store a "length" and overload __repr__ to make the result prettier:
class Prefix:
def __init__(self, length):
self.length = length
def __sub__(self, other):
result_length = self.length - other.length
return Prefix(result_length)
def __repr__(self):
result_m, result_cm = self.split_up(self.length)
if result_m > 0:
return f'{result_m}m {result_cm}cm'
else:
return f'{result_cm}cm'
#staticmethod
def split_up(length):
return divmod(length, 100)
Prefix(220) - Prefix(130)
Output:
90cm
So I defined a function such that it returns a sum of two Time objects as a new Time object, but the sum of the minutes in that resulting Time object cannot exceed 59 and I don't know how to implement that.
Here's my code:
from timer import Time
sum_of_time = Time(0, 0)
sum_of_time.hours= time1.hours + time2.hours
sum_of_time.minutes = time1.minutes + time2.minutes
return sum_of_time
if sum_of_time.minutes >= 60: # where I try to make minutes within 0 to 59
sum_of_time.minutes = sum_of_time.minutes - 60
sum_of_time.hours = sum_of_time.hours + 1
return sum_of_time
This is what datetime.timedelta is used for.
from datetime import timedelta
delta1 = timedelta(hours=1, minutes=30)
delta2 = timedelta(minutes=31)
sum_time = delta1 + delta2
print(sum_time) #2:01:00
You want to get the quotient and remainder when dividing by 60; the quotient gets added to the hour, and the remainder is used as the number of minutes.
sum_of_time = Time(0,0)
hours = time1.hours + time2.hours
minutes = time1.minutes + time2.minutes
q, r = divmod(minutes, 60) # e.g. divmod(117, 60) == (1, 57)
hours += q
minutes = r
sum_of_time.hours = hours
sum_of_time.minutes = minutes
This is logic that should probably be implemented by methods of the Time class. For example:
class Time:
def __init__(self, h, m):
self.hours = 0
self.minutes = 0
# For simplicity here, assume other is an instance of Time
def __add__(self, other):
hours = self.hours + other.hours
minutes = self.minutes + other.minutes
q, r = divmod(minutes, 60)
return Time(hours + q, r)
sum_of_time = time1 + time2
class Time:
def __init__(self,h,m):
self.h = h
self.m = m
q, r = divmod(m, 60)
self.h += q
self.m = r
def __add__(self, o):
return Time(self.h+o.h,self.m+o.m)
def __str__(self):
return "{0}:{1}".format(self.h,self.m)
t1 = Time(1,60)
t2 = Time(1,60)
print (t1+t2)
I am trying to understand why my method, increment4, is not working. All of these methods worked fine as functions, but now that I have converted them into methods something is not working. I have replaced the "Time" object names with "self". I experimented with keeping and deleting "return".
EDIT I was not using dot notation, as was kindly pointed out to me. I made a few changes. Now Python is giving me a different error:
Traceback (most recent call last):
File "/Users//Desktop/temp.py", line 33, in <module>
currenttime.increment4(4000)
File "/Users//Desktop/temp.py", line 22, in increment4
newtime = float(total_seconds).make_time()
AttributeError: 'float' object has no attribute 'make_time'
>>>
Line 33 is:
currenttime.increment4(4000)
Line 22 is:
newtime = float(total_seconds).make_time()
And here is the whole thing:
class Time:
def printTime(self):
print str(time.hours)+":"+str(time.minutes)+":"+str(time.seconds)
def make_time (self):
time = Time ()
time.hours = self / 3600
time.minutes = (self % 3600) / 60
time.seconds = (self % 3600) % 60
return time
def covertTOseconds (self):
hours = self.hours * 3600
minutes = self.minutes * 60
seconds = self.seconds
amt_in_seconds = hours + minutes + seconds
return amt_in_seconds
def increment4 (self, increaseINseconds):
total_seconds = self.covertTOseconds() + increaseINseconds
newtime = float(total_seconds).make_time()
newtime.printTime()
currenttime = Time()
currenttime.hours = 3
currenttime.minutes = 47
currenttime.seconds = 45
currenttime.increment4(4000)
You need to modify your code a little bit:
class Time:
def printTime(self, time):
print str(time.hours)+":"+str(time.minutes)+":"+str(time.seconds)
def increment4(self, increaseINseconds):
seconds = self.covertTOseconds() + increaseINseconds
time = self.makeTime (seconds)
print time
def makeTime(self, totalseconds):
time = Time ()
time.hours = totalseconds / 3600
time.minutes = (totalseconds % 3600) / 60
time.seconds = (totalseconds % 3600) % 60
return time
def covertTOseconds(self):
hours = self.hours * 3600
minutes = self.minutes * 60
seconds = self.seconds
totalseconds = hours + minutes + seconds
return totalseconds
As the error shows converTOseconds is not defined because it should be called with self, also it takes no arguments. Thus, you need to change from covertTOseconds (self) to self.convertTOseconds(). Hope this helps.
Since you have updated the question, it seems to me that what you might want to do is have a class like this:
class Time:
def __init__(self):
self.hours = None
self.minutes = None
self.seconds = None
self.total_seconds = None
def to_seconds(self):
hours = self.hours * 3600
return (self.hours * 3600) + (self.minutes * 60) + self.seconds
def increment(self, x):
self.total_seconds = self.to_seconds() + x
self.hours = self.total_seconds / 3600
self.minutes = (self.total_seconds % 3600) / 60
self.seconds = (self.total_seconds % 3600) % 60
self.__str__()
def __str__(self):
print("{0}:{1}:{2}".format(self.hours, self.minutes, self.seconds))
Then you can use that class as follows:
c_time = Time()
c_time.hours = 3
c_time.minutes = 47
c_time.seconds = 45
c_time.increment(4000)
This outputs:
4:54:25
I am working on the exorcism.io clock exercise and I can not figure out why this test is failing. The results look identical and even have the same type.
Here is my code:
class Clock:
def __init__(self, h, m):
self.h = h
self.m = m
self.adl = 0
def make_time(self):
s = self.h * 3600
s += self.m * 60
if self.adl: s += self.adl
while s > 86400:
s -= 86400
if s == 0:
return '00:00'
h = s // 3600
if h:
s -= h * 3600
m = s // 60
return '{:02d}:{:02d}'.format(h, m)
def add(self, more):
self.adl = more * 60
return self.make_time()
def __str__(self):
return str(self.make_time()) # i don't think I need to do this
if __name__ == '__main__':
cl1 = Clock(34, 37) #10:37
cl2 = Clock(10, 37) #10:37
print(type(cl2))
print(cl2, cl1)
print(cl2 == cl1) #false
A custom class without an __eq__ method defaults to testing for identity. That is to say, two references to an instance of such a class are only equal if the reference they exact same object.
You'll need to define a custom __eq__ method that returns True when two instances contain the same time:
def __eq__(self, other):
if not isinstance(other, Clock):
return NotImplemented
return (self.h, self.m, self.adl) == (other.h, other.m, other.adl)
By returning the NotImplemented singleton for something that is not a Clock instance (or a subclass), you let Python know that the other object could also be asked to test for equality.
However, your code accepts values greater than the normal hour and minute ranges; rather than store hours and minutes, store seconds and normalise that value:
class Clock:
def __init__(self, h, m):
# store seconds, but only within the range of a day
self.seconds = (h * 3600 + m * 60) % 86400
self.adl = 0
def make_time(self):
s = self.esconds
if self.adl: s += self.adl
s %= 86400
if s == 0:
return '00:00'
s, h = s % 3600, s // 3600
m = s // 60
return '{:02d}:{:02d}'.format(h, m)
def __eq__(self, other):
if not isinstance(other, Clock):
return NotImplemented
return (self.seconds, self.adl) == (other.seconds, other.adl)
Now your two clock instances will test equal because internally they store the exact same time in a day. Note that I used the % modulus operator rather than a while loop and subtracting.
I am trying to use the .split method within my "clean" method definition in my "Time" class. Every time I execute the function I am prompted with the error 'Time' object has no attribute 'split'. Here is what I have so far:
def __init__(self, hours=0, minutes=0, seconds=0):
'''hours represents time in hours, minutes represents time in
minutes, and seconds represents time in seconds'''
self.H = hours
self.M = minutes
self.S = seconds
self.clean()
def clean(self):
'''Adjust Time object so that the number of seconds and minutes
is between 0 and 59'''
if isinstance(self.H,str) == True:
self.H = self.split(':')
self.H = self[0]
self.M = self[1]
self.S = self[2]
return self.__str__()
else:
self.S = int(self.H * 3600 + self.M * 60 + self.S)
self.M = int(self.S / 60)
self.H = int(self.M / 60)
self.M = self.M % 60
self.S = self.S % 60
return self.__str__()
So Time("2:33:04") returns a Time object: 02:33:04
Is there any way around this or do I have to define .split within my Time class?
It looks like what you are trying to do is get the class members H from your Time object and split it. I'm not sure this is a great OO design, but if you must do that, it looks like the problem is you are calling split on the class instead of the class member H.
So, in the end you should call self.H.split(':') if you are storing the time as an encoded string in H.
So the code would have to change to:
time_attrs = self.split(':')
self.H = time_attrs[0]
self.M = time_attrs[1]
self.S = time_attrs[2]
return self.__str__()