4

I have a subclass that adds graphics capabilities to a superclass that implements the algorithms. So, in addition to a few extra initialization functions, this subclass will only need to refresh the graphics after the execution of each algorithm-computing function in the superclass.

Classes:

class graph(algorithms):
  ... #initialization and refresh decorators

  @refreshgraph
  def algorithm1(self, *args, **kwargs):
    return algorithms.algorithm1(self, *args, **kwargs)

  @refreshgraph
  def algorithm2(self, *args, **kwargs):
    return algorithms.algorithm2(self, *args, **kwargs)

  ... #and so on

Is there an pythonic way to automatically decorate all the non-private methods defined in the superclass, such that if I add a new algorithm there I don't need to explicitly mention it in my subclass? I would also like to be able to explicitly exclude some of the superclass' methods.

Pato
  • 113
  • 7
  • 2
    What do decorators have to do with it? – kindall Sep 12 '13 at 01:34
  • 1
    decorators are very specific things in Python (and in other languages), so make sure you're using the right terminology. – George Stocker Sep 12 '13 at 01:35
  • I use the word decorators as the same can be accomplished with them. I have rewritten the example to make it obvious. Your edits to the title changed the meaning of my question, though. Thanks! – Pato Sep 12 '13 at 15:36
  • Sounds like a job for a metaclass. Sadly tonight's a bit late for me to write up an answer, maybe I'll get around to it tomorrow... – l4mpi Sep 12 '13 at 22:40
  • By the way, I found a clean approach using the answer of: http://stackoverflow.com/questions/2237624/applying-python-decorators-to-methods-in-a-class – Pato Sep 23 '13 at 20:06

2 Answers2

3

The subclass always gets all the methods from the parent class(es) by default. If you wish to make emulate the behavior other languages use for privacy (eg the 'private' or 'protected' modifiers in C#) you have two options:

1) Python convention (and it's just a convention) is that methods with a single leading underscore in their names are not designed for access from outside the defining class.

2) Names with a double leading underscore are mangled in the bytecode so they aren't visible to other code under their own names. ParentClass.__private is visible inside ParentClass, but can only be accessed from outside ParentClass as ParentClass._ParentClass__private. (Great explanations here). Nothing in Python is truly private ;)

To override an inherited method just define the same name in a derived class. To call the parent class method inside the derived class you can do it as you did in your example, or using super:

def algorithm2(self, *args, **kwargs):
  super(graph, self).algorithm2(self, *args, **kwargs)
  # do other derived stuff here....
  self.refresh()
Community
  • 1
  • 1
theodox
  • 12,028
  • 3
  • 23
  • 36
  • Thanks for the quick answer!. However, my question is not about how to override an inherited method, but how to do it automatically so that all inherited methods get decorated at once. – Pato Sep 12 '13 at 15:14
  • I upvoted, but I think the super call should be: `super(graph, self).algorithm2(*args, **kwargs)` – alejandro Mar 03 '21 at 00:43
0

This is ugly, but I think it does what you want, but without inheritance:

class DoAfter(object):
    def __init__(self, obj, func):
        self.obj = obj
        self.func = func

    def __getattribute__(self, attr, *a, **kw):      
        obj = object.__getattribute__(self, 'obj')

        if attr in dir(obj):
            x = getattr(obj, attr)

            if callable(x):
                def b(*a, **kw):
                    retval = x(*a, **kw)
                    self.func()
                    return retval
                return b
            else:
                return x

        else:
            return object.__getattribute__(self, attr)

Use it like this:

>>> class A(object):
...     def __init__(self):
...         self.a = 1
... 
...     def boo(self, c):
...         self.a += c
...         return self.a
>>> def do_something():
...     print 'a'
>>> a = A()
>>> print a.boo(1)
2
>>> print a.boo(2)
4
>>> b = DoAfter(a, do_something)
>>> print b.boo(1)
a
5
>>> print b.boo(2)
a
7

A increments a counter each time A.boo is called. DoAfter wraps A, so that any method in the instance a can be called as if it were a member of b. Note that every method is wrapped this way, so do_something() is called whenever a method is accessed.

This is barely tested, not recommended, and probably a bad idea. But, I think it does what you asked for.

EDIT: to do this with inheritance:

class graph(algorithms):
    def refreshgraph(self):
        print 'refreshgraph'

    def __getattribute__(self, attr):
        if attr in dir(algorithms):
            x = algorithms.__getattribute__(self, attr)

            if callable(x):
                def wrapped(*a, **kw):
                    retval = x(*a, **kw)
                    self.refreshgraph()
                    return retval
                return wrapped
            else:
                return x

        else:
            return object.__getattribute__(self, attr)
Neil
  • 2,378
  • 1
  • 20
  • 28
  • Thanks! but I need to have all the class and OOP construction hidden from the final user: `result=graph(data).algorithm1().algorithm2()` – Pato Sep 12 '13 at 21:16
  • I added a modification that uses inheritance, but I don't think it's a better way to do this. – Neil Sep 12 '13 at 22:03