2

Write a Boolean function between that takes two MyTime objects, t1 and t2, as arguments, and returns True if the invoking object falls between the two times. Assume t1 <= t2, and make the test closed at the lower bound and open at the upper bound, i.e. return True if t1 <= obj < t2.

Now from the wording of this question, it seems like there should only be two arguments in the function, but I cannot see a way to make such a function by only using two arguments. I mean I guess you could make another function that creates a variable that is a MyTime object, but I was only going to keep it to one function and not make two. The wording of the question makes it seem like you should have Object(Function(t1,t2)) but I dont think that is possible. Is it possible to make the 'between' function with only two arguments? Here is my code

class MyTime:
        """ Create some time """

    def __init__(self,hrs = 0,mins = 0,sec = 0):
        """Splits up whole time into only seconds"""
        totalsecs = hrs*3600 + mins*60 + sec
        self.hours = totalsecs // 3600
        leftoversecs = totalsecs % 3600
        self.minutes = leftoversecs // 60
        self.seconds = leftoversecs % 60
    def __str__(self):
        return '{0}:{1}: 
             {2}'.format(self.hours,self.minutes,self.seconds)

    def to_seconds(self):
        # converts to only seconds
        return (self.hours * 3600) + (self.minutes * 60) + self.seconds

def between(t1,t2,x):
    t1seconds = t1.to_seconds()
    t2seconds = t2.to_seconds()
    xseconds = x.to_seconds()
    if t1seconds <= xseconds  < t2seconds:
        return True
    return False


currentTime = MyTime(0,0,0)
doneTime = MyTime(10,3,4)
x = MyTime(2,0,0)
print(between(currentTime,doneTime,x))
user3483203
  • 50,081
  • 9
  • 65
  • 94
Matt
  • 41
  • 5
  • 1
    You just need a class method, `def between(self, t1, t2):` would be within the class definition. Now you invoke it with `x.between(t1, t2)`. – AChampion Jul 16 '18 at 00:28
  • The terminology is a little weird in the question. The only use of "invoking object" I know of is in Smalltalk, and it doesn't mean what the assignment wants it to mean (it's the `self` in scope at the place where you call the method, and there isn't one f those here, or in Python in general; the thing you call the method on is the "receiving object" or "receiver"). If your textbook/teacher/whatever has been teaching and consistently using this slightly idiosyncratic terminology, you probably need to study up on your notes. If not, you may want to let them it's confusing. – abarnert Jul 16 '18 at 00:36
  • 2
    Careful with terminology @AChampion. `@classmethod` is different from a normal method. We do not want a classmethod. – gilch Jul 16 '18 at 00:36
  • @gilch True, a method in the class would have been better. – AChampion Jul 16 '18 at 00:37
  • 1
    Also, saying "write a function" instead of "write a method" is also misleading here, maybe even a trick question. It's technically correct (because in Python, the way you write a method is to write a function), but any normal person who reads it is going to be put off from thinking about putting the `def` inside the `class`, even though that's pretty clearly what you're supposed to do. – abarnert Jul 16 '18 at 00:40
  • @AChampion The usual terminology is [instance method](https://stackoverflow.com/questions/17134653/difference-between-class-and-instance-methods). Also discussed [here](https://softwareengineering.stackexchange.com/questions/306092/what-are-class-methods-and-instance-methods-in-python) – PM 2Ring Jul 16 '18 at 00:41
  • yea the first part of the question is to simply make a function and the second part is to turn it into a method – Matt Jul 16 '18 at 12:32

2 Answers2

5

You are 100% correct, it does need three parameters. If you write it as a member function of the MyTime class, it gets a third parameter, self:

class MyTime():

    # the guts of the class ...

    def between(self, t1, t2):
        t1seconds = t1.to_seconds()
        t2seconds = t2.to_seconds()
        myseconds = self.to_seconds()

        return t1seconds <= myseconds < t2seconds

You can use this method with:

currentTime = MyTime(0, 0, 0)
doneTime = MyTime(10, 3, 4)
x = MyTime(2, 0, 0)
x.between(currentTime, doneTime)

The self argument is passed in automatically by calling the method on an instance of the class.

jeremye
  • 1,368
  • 9
  • 19
  • This isn't quite right. The definition needs three _parameters_, but the call only needs two _arguments_. In `x.between(currentTime, doneTime)` there's a bound method (`x.between`) and a call with two arguments. – abarnert Jul 16 '18 at 02:01
  • Thanks for the help! – Matt Jul 16 '18 at 12:33
  • @abarnert Interesting distinction. I was not familiar, thanks! I'm glad that you linked to the python docs, I really should read through more of them, there's so much to learn. – jeremye Jul 17 '18 at 00:47
  • @illiteratecoder Yes. Although this is a bit annoying across languages. IIRC, K&R first screwed it up, by replacing the ALGOL terms "formal parameter" and "actual parameter" with "parameter" and "argument", which is what Python follows, but then not using them consistently, and then ANSI C redefined "parameter" to mean specifically only the typed parameters in a full prototype declaration, then some of the early languages with generics reintroduced formal-actual and repurposed the parameter-argument distinction, so `def f(t: T)` has formal argument `t` and formal parameter `T`… – abarnert Jul 17 '18 at 00:55
1

The problem seems to be written as a trick question—or maybe just accidentally so. So, let's get some terminology straight, so we can really understand what it's asking for.

  • The variable names in a function definition are parameters.

  • The expressions inside the parentheses of a function call are arguments.

Of course in the simplest case, each parameter gets bound to exactly one argument, but that isn't true in cases involving, e.g., *args or **kw (on either side), or default values, or method calls.


So, between obviously needs three parameters—but that doesn't mean it needs three arguments, if you can find some other reasonable way to specify the value for one of those parameters.

And, while the way the problem is worded disguises the most obvious answer, it's still the most obvious answer: what you want here is a method, defined inside the class MyTime: definition, exactly as described in illiteratecoder's answer (which I'll copy here):

def between(self, t1, t2):
    t1seconds = t1.to_seconds()
    t2seconds = t2.to_seconds()
    myseconds = self.to_seconds()

    return t1seconds <= myseconds < t2seconds

Of course if you really want to, you can call this with three arguments:

MyTime.between(x, currentTime, doneTime)

But normally, you won't call the function directly, you'll call it as a bound method:

x.between(currentTime, doneTime)

Of course, as the glossary entry for methods implies, under the covers, this method call with two arguments gets turned into a function call with three arguments, by some code inside the guts of types.MethodType. But there's no three-argument call in your code, or anywhere else.


Apparently, x (or obj, in the original statement) is what the problem meant by the phrase "invoking object", even though that's a very weird use of terminology.1


If you're curious, the code (or, rather, the Python equivalent of the C code) that does that looks like this:

def __call__(self, *args, **kw):
    return self.__func__(self.__self__, *args, **kw)

… where self.__func__ is MyTime.between and self.self is x.


1. I've never heard "invoking object" used in Python. It is used in Smalltalk and related languages, but it means the self in scope at the lexical location of the message send (method call), which is meaningless here, and generally meaningless in Python (unlike, e.g., JavaScript). The equivalent of the x in x.between is definitely not the invoking object, it's the receiving object. So, if this is a trick question, I think they overstepped the bounds between misleading but still technically accurate and just plain wrong, which is cheating. But if, on the other hand, your teacher or book or whatever has been consistently using this idiosyncratic terminology, then it's not really wrong, just a little weird, and you probably need to go back and study some notes to make sure you understand their terminology, at least while trying to get through this course.

abarnert
  • 354,177
  • 51
  • 601
  • 671