I'm going through a Python OOPs book by Dusty Phillips. I fail to understand a particular program in the book, chapter 7 - Python Object-oriented Shortcuts. The extended version of the code is available here
Although the program comes under the topic Functions are objects too, the provided program also uses a strange code, which i feel, more of imply the opposite (using objects as functions).
I have pointed out the line in the code where i have the doubt. How is that variable callback of TimedEvent used like a function Timer class ? What is going on here in this part.
import datetime
import time
class TimedEvent:
def __init__(self, endtime, callback):
self.endtime = endtime
self.callback = callback
def ready(self):
return self.endtime <= datetime.datetime.now()
class Timer:
def __init__(self):
self.events = []
def call_after(self, delay, callback):
end_time = datetime.datetime.now() + \
datetime.timedelta(seconds=delay)
self.events.append(TimedEvent(end_time, callback))
def run(self):
while True:
ready_events = (e for e in self.events if e.ready())
for event in ready_events:
event.callback(self) ----------------> Doubt
self.events.remove(event)
time.sleep(0.5)
2 Answers 2
Both are true
- functions are objects: do a
dir(f)on a function to view its attributes - objects can be used as functions: just add
__call__(self, ...)method and use the object like a function.
In general things that can be called using a syntax like whatever(x, y, z) are called callables.
What the example is trying to show is that methods are just object attributes that are also callables. Just like you can write obj.x = 5, you can also write obj.f = some_function.
8 Comments
object.f. A method is a function that has already been passed the self argument (that's the important part of the definition, doesn't matter where they are defined). Look into the descriptor protocol on how that happens. Descriptors are really interesting, they explain various aspects of python.self is written explicitly in the code, but it's not passed by the programmer, it's passed by the interpreter. That happens using the descriptor protocol when the function is looked up using the dot. But, it's really complicated, if you are interested look into descriptors.self.callback = callback (where the right-hand callback is that function), and then later called?Yes, that example indeed shows that functions are object. You can assign an object to the callback attribute and this tries to show that the object you assign to callback can be a function.
class TimedEvent:
def __init__(self, endtime, callback):
self.endtime = endtime
self.callback = callback
What is missing to make it clear is the initialization. You could, for example, do this:
def print_current_time():
print(datetime.datetime.now().isoformat())
event = TimedEvent(endtime, print_current_time)
event.callback()
This will actually call print_current_time, because event.callback is print_current_time.
callbackinitialised? You don’t show that part. Is a function assigned to it? Or something else?call_afteris called! Looking at the linked code,call_afteris always invoked with a regular function forcallback. Socallback... just contains a function.