2

I am looking for the way how to implement an object that has overwritable event handlers.

Here's a non-working code that I'd like to adjust so that it is working:

class Button(object):
  def __init__(self, id):
    self.id = id
    pass
  def trigger_on_press(self):
    self.on_press()
  def trigger_on_release(self):
    self.on_release()
  def on_press(self):
    # empty handler
    print("Just an empty on_press handler from id=%s" % self.id)
    pass
  def on_release(self):
    # empty handler
    print("Just an empty on_release handler from id=%s" % self.id)
    pass

btn = Button("btn")
btn.trigger_on_press()

def custom_handler(self):
  print("Event from id=%s" % self.id)

btn.on_press = custom_handler
btn.trigger_on_press()

How can I overwrite the default empty on_press method for that particular instance so that it is properly passed the self reference?

1
  • 2
    pass statements are useless Commented Apr 27, 2019 at 11:20

2 Answers 2

1

I would suggest an approach like this: you directly have an attribute (in this case func_on_press) that holds a reference to a function (not a method). That function receives a single argument which will be the object (I called it obj instead of self to make it clear that it is a function).

def default_empty_event_handler(obj):
    print('empty handler for id={}'.format(obj.the_id))

class Button:
    def __init__(self, the_id):
        self.the_id = the_id
        self.func_on_press = default_empty_event_handler
        self.func_on_release = default_empty_event_handler

    def trigger_on_press(self):
        self.func_on_press(self)    # we pass 'self' as argument to the function

    def trigger_on_release(self):
        self.func_on_release(self)  # we pass 'self' as argument to the function

Now you can change that attribute as you go:

btn = Button('btn')
print('first trigger')
btn.trigger_on_press()

def custom_handler(obj):
    print('custom handler for id={}'.format(obj.the_id))

btn.func_on_press = custom_handler
print('second trigger')
btn.trigger_on_press()

This will give the following output:

first trigger
empty handler for id=btn
second trigger
custom handler for id=btn

In my opinion this greatly reduces the code of the class (you define less methods) and is easily understandable. Does that work for you?

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this works fine, however the duplicate question referenced by @Sanyash tifs me more. It feels more natural to call the event methods as normal methods, especially if I'd call them directly from the instance variable.
0

the key is to use the class name in new assignement not the object

change btn.on_press = custom_handler to Button.on_press = custom_handler and magically it works

Explanation:

when you call btn.on_press() it will be translated to its original call of `Button.on_press(btn)', so you need to change the call in the blueprint not the object

your example:

class Button(object):
  def __init__(self, id):
    self.id = id
    pass
  def trigger_on_press(self):
    self.on_press()
  def trigger_on_release(self):
    self.on_release()
  def on_press(self):
    # empty handler
    print("Just an empty on_press handler from id=%s" % self.id)
    pass
  def on_release(self):
    # empty handler
    print("Just an empty on_release handler from id=%s" % self.id)
    pass

btn = Button("btn")
btn.trigger_on_press()

def custom_handler(self):
  print("Event from id=%s" % self.id)

Button.on_press = custom_handler  # here use the class name not obj name
btn.trigger_on_press()

output:

Just an empty on_press handler from id=btn
Event from id=btn

1 Comment

This approach ovewrites the class method for all instances. Add btx = Button("btx"); btx.trigger_on_press() to the code and you'll see that it's already spoiled.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.