Delegates in python
Asked Answered
A

3

22

I've implemented this short example to try to demonstrate a simple delegation pattern. My question is. Does this look like I've understood delegation right?

class Handler:
    def __init__(self, parent = None):
        self.parent = parent
    def Handle(self, event):
        handler = 'Handle_' +event
        if hasattr(self, handler):
            func = getattr(self, handler)
            func()
        elif self.parent:
            self.parent.Handle(event)

class Geo():
    def __init__(self, h):
        self.handler = h

    def Handle(self, event):
        func = getattr(self.handler, 'Handle')
        func(event)

class Steve():
    def __init__(self, h):
        self.handler = h

    def Handle(self, event):
        func = getattr(self.handler, 'Handle')
        func(event)

class Andy():
    def Handle(self, event):
        print 'Andy is handling %s' %(event)

if __name__ == '__main__':        
    a = Andy()
    s = Steve(a)
    g = Geo(s)
    g.Handle('lab on fire')
Armful answered 4/9, 2010 at 18:47 Comment(3)
What are you doing with the Handler class?Glib
This is all part of a bigger example, and I forgot to get rid of it when I posted it here.Armful
In the code above, your Geo, Steve and Andy class have a Handle function in which you call getattr(). I recommand to check the function really exists in the delegate object with hasattr() before calling getattr. I just wanted to point that out because it could be a source of crashes.Intersex
S
10

That's the basic concept, yes - passing on some incoming request to another object to take care of.

Skitter answered 4/9, 2010 at 19:10 Comment(0)
C
18

One Python tip: you don't need to say:

func = getattr(self.handler, 'Handle')
func(event)

just say:

self.handler.Handle(event)

I'm not sure what you are doing with your Handler class, it isn't used in your example.

And in Python, methods with upper-case names are very very unusual, usually a result of porting some existing API with names like that.

Clarino answered 4/9, 2010 at 19:39 Comment(1)
Thanks Ned, it's part of greater example using the Command Dispatch pattern which is why I'm using getattr, thanks for noticing the bad method name, I'll fix thatArmful
S
10

That's the basic concept, yes - passing on some incoming request to another object to take care of.

Skitter answered 4/9, 2010 at 19:10 Comment(0)
M
1

Was wondering the same thing as well, Python does not seem to support delegates as a built-in feature, and expanding with a lot of opensrc libs on this type of ground-level stuff is sometimes severe quality risk tbh as you add a dependency to 3rd party in more or less critical area, surely it depends entirely on the package and if its actively developed but still.

I found it helpful long time ago to understand more on delegates through C#, there are good docs that explain them well.

Looking at the comments, I read Ashbay suggest you to making sure that functions exist in your classes with hasattr(). Now, as you're using delegates in multiple classes, instead of function delegation (see C#, has good explanation), then why would you not implement an interface for this "code safety feature (its good point by the way!)" in your classes you wish to offer delegates:

  • You can drop function call (saves one process run) by defining an Interface for your real classes "as a contract".
  • This contract ensures that everything that is contracted have always been implemented in your class hierarchy chain in such way the contracts agreed are fulfilled.

NOTE: Interfaces are often done with the built-in abc python package (abstract base class) --> See why its a bit clumsy to be use abc-package (abstract classes) to define interface class: https://interface.readthedocs.io/en/latest/abc.html

Unluckily they are not yet built-in, but here it is anyhow: https://pypi.org/project/python-interface/#description

  • Through this project you can however get such common feature (why it was even / is still missing from Python, as this is fundamentally important in robust OoP!), as external libs are always one xtra dependency (that might or might not deprecate in near future).

  • you can make the classes more generic, with heritance of parent class, usually with interfaces you can contract them to parent class, and then mark abstract and "pass" incase you wish to implement them in children. You should do that only if the implementation truly changes/needs to have differences, otherwise just make it generic for all (saves a lot coding time and code duplication if you inherit a lot---> thus using abstract base-classes with abstract methods are a disastrous pattern alone).

  • not sure if python offers good means for making virtual overriding like in C#, where you can use "best from both", so that you can override only when you really need and then by default use that parent class implementation. Most likely it can be done, but python is a bit "rebellious" as it has many things done slightly differently :) However, it looks to be that the interface python package in above link has some support at least for these.

Also, found this blog that talks about the topic offering multiple options: https://michaelcho.me/article/method-delegation-in-python

the delegator in his option3 is probably referring likely to this lib: https://pypi.org/project/ObjectDelegator/

Personal opinion is that if you can and have time to design your class level architecture more accurately, you should not need delegates in most of the cases at all. Delegates should be more like your "last resort" in terms of trying to make your code more generic and utilizable in a loop structures. Anyhow, sometimes (but rarely) you do need them.

ps. my first stack overflow comment ever, I apologize if I failed to be correct on some look-n-feel etc. styling issues :)

Marche answered 15/8, 2023 at 8:15 Comment(1)
Welcome to SO. Lemme give you your first upvote. :^)Ogdon

© 2022 - 2024 — McMap. All rights reserved.