Class and external method call
Question: I am going through a data structures course and I am not understanding how a
Class can call a method that's in another Class.  
The code below has 2 classes: `Printer` and `Task`.  
Notice that class `Printer` has a method called `startNext`, and this has a
variable `self.timeRemaining` that gets assigned the result of
`newTask.getPages() * 60/self.pagerate`.

How can `newTaks` reference the `getPages()` method from the Task class?  
The code that passes this object to the Printer class never references the
Task class.  
The code works, since this is what the course gives out but, I just cannot
understand how that method is accessed.  
Code:

    
    
    from pythonds.basic.queue import Queue
    
    import random
    
    class Printer:
    
        def __init__(self, ppm):
            self.pagerate = ppm
            self.currentTask = None
            self.timeRemaining = 0
    
        def tick(self):
            if self.currentTask != None:
                self.timeRemaining = self.timeRemaining - 1
    
                if self.timeRemaining <= 0:
                    self.currentTask = None
    
        def busy(self):
            if self.currentTask != None:
                return True
            else:
                return False
    
        def startNext(self, newTask):
            self.currentTask = newTask
            self.timeRemaining = newTask.getPages() * 60/self.pagerate
    
    class Task:
    
        def __init__(self, time):
            self.timeStamp = time
            self.pages = random.randrange(1, 21)
    
        def getStamp(self):
            return self.timeStamp
    
        def getPages(self):
            return self.pages
    
        def waitTime(self, currentTime):
            return currentTime - self.timeStamp
    
    def simulation(numSeconds, pagesPerMinute):
    
        labPrinter = Printer(pagesPerMinute)
        printQueue = Queue()
        waitingTimes = []
    
        for currentSecond in range(numSeconds):
    
            if newPrintTask():
                task = Task(currentSecond)
                printQueue.enqueue(task)
    
            if (not labPrinter.busy()) and (not printQueue.isEmpty()):
                nextTask = printQueue.dequeue()
                waitingTimes.append(nextTask.waitTime(currentSecond))
                labPrinter.startNext(nextTask)
    
            labPrinter.tick()
    
        averageWait = sum(waitingTimes)/len(waitingTimes)
        print "Average Wait %6.2f secs %3d tasks remaining." % (averageWait, printQueue.size())
    
    def newPrintTask():
        num = random.randrange(1, 181)
    
        if num == 180:
            return True
        else:
            return False
    
    for i in range(10):
        simulation(3600, 5)
    


Answer: If I understand clearly your question, it is because you are adding task
object to Queue list. Then when you are getting object (list item) back, you
are getting again Task object:

    
    
    #creating Task object and adding to Queque list
    task = Task(currentSecond)
    printQueue.enqueue(task)
    
    class Queue:
        def __init__(self):
            #list of task objects
            self.items = []
    
        def enqueue(self, item):
            #you are inserting Task object item to list
            self.items.insert(0,item)
    
        def dequeue(self):
           #returns task object
           return self.items.pop()
    

So then you can call startNext() method from Printer class, because the
dequeue() method is returning Task object.

And because of the object in startNext() is type of Task, you can call
getPages() method on that object.

Is it sufficient answer?

