On Thu, Oct 9, 2014 at 11:30 AM, kracekumar ramaraju < kracethekingma...@gmail.com> wrote:
> On Wed, Oct 8, 2014 at 4:19 PM, Anand Chitipothu <anandol...@gmail.com> > wrote: > > > Hi, > > > > I'm working on a slightly large application and I'm trying to model it > as a > > some kind of plugin architecture so that it modular and I can enable or > > take out features without lot of code changes. > > > > One of the issues I faced was that the wanted to add some methods to a > > class only when a feature/plugin is enabled. > > > > Here is a simplified version of what I have: > > > > class Place(Mixable): > > def __init__(self, name): > > self.name = name > > > > def get_users(self): > > return "users-of-{}".format(self.name) > > > > def get_links(self): > > return "links-of-{}".format(self.name) > > > > There are couple of issues with this. > > > > 1. The logic for computing users or links doesn't really belong to this > > file. I wanted to that in a separate module for modularity. > > > > 2. The Place class will become too large to manage over time. > > > > So, I came up with the following approach to address these issues. > > > > # place.py > > > > class Mixable(object): > > """Magic class to allow adding mixins to the class at run-time. > > """ > > @classmethod > > def mixin(cls, mixin): > > """Decorator to add a mixin to the class runtime. > > """ > > cls.__bases__ = cls.__bases__ + (mixin,) > > > > class Place(Mixable): > > def __init__(self, name): > > self.name = name > > > > # users.py > > @Place.mixin > > class UsersMixin(object): > > def get_users(self): > > return "users-of-{}".format(self.name) > > > > > Is there any specific reason for using decorators ? > Just because I felt that provides a nice API. I would have used a more explicit approach like the following, but I liked the decorators one better. def setup_plugin(): register_place_plugin(UsersMixin) > # links.py > > @Place.mixin > > class LinksMixin(object): > > def get_links(self): > > return "links-of-{}".format(self.name) > > > > p = Place('bangalore') > > print(p.get_users()) > > print(p.get_links()) > > > I somehow feel this can lead to unexpected behaviour since Mixable classes > are added at various files. > Yes, it requires some discipline. > This pattern looks like global variable argument (global variables are > bad). Say if Idecorate Foo with @Place.mixin by mistake, behaviour of the > Foo will be available in Place class and leads to side effect. > Well that is a compromise. Same as Flask vs. Django URL routing. > > How about > > #dispatcher.py > # import all the classes > > def get_place_class(): > # Check for features > for cls in classes: > Place.__bases__ = Place.__bases__ + (cls,) > return Place > That should be setup_place_class() and that should be called only once. But the decorators approach makes calling it twice impossible. > > With this I was able to split the class into 3 files and now I have > > flexibility of deciding which features enable from a config file. > > > > What do you guys think of this approach? > > > > My only concern base classes are added in different files and difficult to > remember. > Yes, it will become difficult if not used with care, but I think it can be used very elegantly if enough care is given. What I really want is multiple people work on separate parts of the system without having to touch the core code. > Is this a good practice? > > Are there any know flaws in this approach? > > How did you solve that issue when you faced similar situation? > > > > > Did I understand the problem correctly ? > I think so. Anand _______________________________________________ BangPypers mailing list BangPypers@python.org https://mail.python.org/mailman/listinfo/bangpypers