ActiveState Code

Recipe 284528: A nicer syntax for super(cls,self)


Makes cooperative calls looks nicer: super.method instead of super(cls,self).method .

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"""Implements a nice syntax for cooperative methods.
Could be made working for staticmethods and classmethods,
but who needs them anyway? ;)"""

import inspect

def second_arg(func):
    args = inspect.getargspec(func)[0]
    if len(args) >= 2: return args[1]

class _Cooperative(type):
    def __init__(cls, name, bases, dic):
        for n,func in dic.iteritems():
            setattr(cls, n, func)
    def __setattr__(cls, name, func):
        set = super(_Cooperative, cls).__setattr__
        if inspect.isfunction(func) and second_arg(func) == "super":
            set(name, lambda self, *args, **kw : 
                func(self, super(cls, self), *args, **kw))
        else:
            set(name, func)

class Cooperative:
    __metaclass__ = _Cooperative


if __name__ == "__main__":
    class B(Cooperative):
        def print_(self):
            print "B",
    class C(B):
        def print_(self, super):
            super.print_()
            print "C",
    class D(C):
        def print_(self, super):
            super.print_()
            print "D",
    D().print_() # => B C D

Discussion

For the purpose of this recipe, cooperative methods are methods with a second argument called "super": super.method(args, *kw) is then a shortcut for super(cls,self).method(args, *kw). This avoids to repeat the name of the class in the super object, a thing I always loathed.

To use it, just import the Cooperative class and put it on top of your hierarchies. If you use multiple metaclasses, you may want to give a look to my recipe about removing metaclass conflicts.

I could make this recipe to work for staticmethods and classmethods, but I didn't bothered since I wanted to keep the cooperative module under the twenty lines.

This is just a hack, waiting for a nicer "super" built-in ...

Comments

  1. 1. At 3:28 a.m. on 27 may 2004, Gonçalo Rodrigues said:

    What if you need to spell out the class? I can rememer two places in my code where naming the class explicitly was helpful.

    1. In a class i needed to get not the super method but the grand-super method. I can't remember exactly why I needed it, but looking back, it must have been a case of bad design.

    2. The following is not bad design, but a real need that came up:

      class SuperGetter(object): def __init__(self, cls, attrib): super(Super, self).__init__(cls) self.__cls__ = cls self.__attrib__ = attrib

      def get(self, inst):
          return getattr(super(cls, inst), self.attrib)
      

    And variations thereof.

  2. 2. At 4:26 a.m. on 28 may 2004, Gonçalo Rodrigues said:

    What if you need to spell out the class exactly? I have two use cases, where it actually was useful to be able to name the super class explicitly. One was, when I needed to get the grand-super implementation, that is

    class A(object):
        def method(self, args):
            ...
    
    class B(A):
        def method(self, args):
            super(B, self).method(args)
            ...
    
    class C(B)
    
        def method(self, args):
            #We want the grand-super (B), not super (C).
            super(B, self).method(args)
            ...
    

    I can't remember the exact circumstances where I needed that, so quite possibly this was just a case of bad design. The following, I don't thing it is:

    class SuperGetter(object):
        def __init__(self, cls, attrib):
            self.cls = cls
            self.attrib = attrib
    
        def __call__(self, inst, args):
            func = getattr(super(cls, inst), attrib)
            return func(args)
    

    And variations, thereof.

  3. 3. At 9:40 p.m. on 10 jun 2004, Michele Simionato (the author) said:

    Maybe I was unclear. I am not advocating replacing the current two-argument syntax of 'super'. We need it. I am just advocating for some syntactic sugar in the common cases where the first argument is the current class. No more than that.

Sign in to comment