super. could there be a simpler super?

Discussion in 'Python' started by Kerim Borchaev, Jan 15, 2004.

  1. Hello!

    Always when I use "super" I create a code duplication because class
    used as first arg to "super" is always the class where the method
    containing "super" was defined in:
    '''
    class C:
    def method(self):
    super(C, self).method()
    '''

    Obviously the methods like the one below doesn't work "right";-)
    '''
    def super(self):
    super(self.__class__, self)
    class C:
    def method(self):
    super(self).method()
    '''

    Is it possible that such a "super"(deducing class method declaration
    context) could appear in Python?
    (It seems to me that to implement a simple super something should be
    done during "compilation" of class declaration.)

    Best regards,
    Kerim mailto:
    Kerim Borchaev, Jan 15, 2004
    #1
    1. Advertising

  2. Kerim Borchaev <>:
    > Is it possible that such a "super"(deducing class method declaration
    > context) could appear in Python?
    > (It seems to me that to implement a simple super something should be
    > done during "compilation" of class declaration.)


    The document "Unifying types and classes in Python 2.2" by Guido
    probably answers your question.

    Quote from http://www.python.org/2.2.3/descrintro.html#cooperation
    regarding super:

    "It would be nice if we didn't have to name the class explicitly, but
    this would require more help from Python's parser than we can
    currently get. I hope to fix this in a future Python release by making
    the parser recognize super."

    --
    Kristian Ovaska - http://www.cs.helsinki.fi/u/hkovaska/en/
    Kristian Ovaska, Jan 15, 2004
    #2
    1. Advertising

  3. On Thu, 15 Jan 2004 11:50:57 +0300, Kerim Borchaev <>
    wrote:

    >Hello!
    >
    > Always when I use "super" I create a code duplication because class
    > used as first arg to "super" is always the class where the method
    > containing "super" was defined in:
    > '''
    > class C:
    > def method(self):
    > super(C, self).method()
    > '''
    >
    > Obviously the methods like the one below doesn't work "right";-)
    > '''
    > def super(self):
    > super(self.__class__, self)
    > class C:
    > def method(self):
    > super(self).method()
    > '''


    Hmm... I once used super where the class used as first arg was *not*
    the class defining the method, it was it's super class. So I was
    calling, not the super method, but it's grand-super method.

    Arguably, this is a clear sign of bad design on my part. But that's
    how it went, anyway.

    With my best regards,
    G. Rodrigues
    Gonçalo Rodrigues, Jan 15, 2004
    #3
  4. Kerim Borchaev

    Gerrit Holl Guest

    Kristian Ovaska wrote:
    > Kerim Borchaev <>:
    > > Is it possible that such a "super"(deducing class method declaration
    > > context) could appear in Python?
    > > (It seems to me that to implement a simple super something should be
    > > done during "compilation" of class declaration.)

    >
    > The document "Unifying types and classes in Python 2.2" by Guido
    > probably answers your question.
    >
    > Quote from http://www.python.org/2.2.3/descrintro.html#cooperation
    > regarding super:
    >
    > "It would be nice if we didn't have to name the class explicitly, but
    > this would require more help from Python's parser than we can
    > currently get. I hope to fix this in a future Python release by making
    > the parser recognize super."


    Another quote from the same page :) :

    --- start quote ---
    Our second example creates a class, 'autosuper', which will add a
    private class variable named __super, set to the value super(cls).
    (Recall the discussion of self.__super above.) Now, __super is a private
    name (starts with double underscore) but we want it to be a private name
    of the class to be created, not a private name of autosuper. Thus, we
    must do the name mangling ourselves, and use setattr() to set the class
    variable. For the purpose of this example, I'm simplifying the name
    mangling to "prepend an underscore and the class name". Again, it's
    sufficient to override __init__ to do what we want, and again, we call
    the base class __init__ cooperatively.

    class autosuper(type):
    def __init__(cls, name, bases, dict):
    super(autosuper, cls).__init__(name, bases, dict)
    setattr(cls, "_%s__super" % name, super(cls))

    Now let's test autosuper with the classic diamond diagram:

    class A:
    __metaclass__ = autosuper
    def meth(self):
    return "A"
    class B(A):
    def meth(self):
    return "B" + self.__super.meth()
    class C(A):
    def meth(self):
    return "C" + self.__super.meth()
    class D(C, B):
    def meth(self):
    return "D" + self.__super.meth()

    assert D().meth() == "DCBA"

    (Our autosuper metaclass is easily fooled if you define a subclass with
    the same name as a base class; it should really check for that condition
    and raise an error if it occurs. But that's more code than feels right
    for an example, so I'll leave it as an exercise for the reader.)

    --- end quote ---

    yours,
    Gerrit.
    --
    164. If his father-in-law do not pay back to him the amount of the
    "purchase price" he may subtract the amount of the "Purchase price" from
    the dowry, and then pay the remainder to her father's house.
    -- 1780 BC, Hammurabi, Code of Law
    --
    PrePEP: Builtin path type
    http://people.nl.linux.org/~gerrit/creaties/path/pep-xxxx.html
    Asperger's Syndrome - a personal approach:
    http://people.nl.linux.org/~gerrit/english/
    Gerrit Holl, Jan 15, 2004
    #4
  5. Kerim Borchaev <> wrote in message news:<>...
    > Hello!
    >
    > Always when I use "super" I create a code duplication because class
    > used as first arg to "super" is always the class where the method
    > containing "super" was defined in:
    > '''
    > class C:
    > def method(self):
    > super(C, self).method()
    > '''
    >
    > Obviously the methods like the one below doesn't work "right";-)
    > '''
    > def super(self):
    > super(self.__class__, self)
    > class C:
    > def method(self):
    > super(self).method()
    > '''
    >
    > Is it possible that such a "super"(deducing class method declaration
    > context) could appear in Python?
    > (It seems to me that to implement a simple super something should be
    > done during "compilation" of class declaration.)
    >
    > Best regards,
    > Kerim mailto:


    ``super`` is one of the trickiest Python constructs. In
    http://www.python.org/2.2.3/descrintro.html Guido sketches
    a metaclass solution which however is not quite satisfactory (for one,
    it does not work with magic methods).

    Some time ago I went to "fix" autosuper, but that required a major metaclass
    hacking which was so deep that I have already forgotten what I did ;)
    Nevertheless, I have still the files around, and my test suite runs okay
    (this only means that the bugs are smarter than me) so I think I will post
    the code. If somebody uses it and finds an unexpected behavior, please
    send me a note. If somebody wants his head to explode, please try to
    understand what safetype does ;)

    Here are two examples of usage:

    # example1.py: the diamond diagram

    from super import autosuper

    class A(object):
    __metaclass__=autosuper
    def m(self):
    return "A"
    class B(A):
    def m(self):
    return "B" + self.__super.m()
    class C(A):
    def m(self):
    return "C" + self.__super.m()
    class D(C, B):
    def m(self):
    return "D" + self.__super.m()

    print D().m()

    this prints DCBA.

    #example2.py

    from super import autosuper

    class A(str):
    __metaclass__=autosuper
    def __new__(cls):
    obj='A'+cls.__super.__new__(cls)
    print obj
    return obj
    class B(A):
    def __new__(cls):
    obj="B" + cls.__super.__new__(cls)
    print obj
    return obj
    class C(A):
    def __new__(cls):
    obj="C" + cls.__super.__new__(cls)
    print obj
    return obj
    class D(C, B):
    def __new__(cls):
    obj="D" + cls.__super.__new__(cls)
    print obj
    return obj

    D()

    this prints

    A
    BA
    CBA
    DCBA

    Here is the module super.py:

    # super.py

    from safetype import safetype # deep magic to avoid metaclass conflicts

    class _super(object):
    """Helper descriptor, called by the ``Enable__super`` metaclass which will
    take care of defining the ``__thisclass__`` attribute; it should not be
    called directly, unless you really know what you are doing. Notice that
    this ``_super`` is minimal, i.e. it does not define ``__new__``,
    `` __init__`` or other special methods; this avoids the problems of the
    standard ``super``."""
    def __get__(self,obj,klass):
    if obj is None: obj=klass
    return super(self.__thisclass__,obj)

    class autosuper(safetype):
    """Cooperative safe metaclass which defines a private attribute ``__super``
    on its instances, containing a reference to the descriptor ``_super``.
    This enable the cooperative syntax ``obj.__super.methodname`` as
    sugar for ``super(callingclass,obj).methodname``."""
    def __init__(cls,*args):
    super(autosuper,cls).__init__(*args)
    if len(args)==1 or args[0]=='superobject': return # do nothing
    strippedname=args[0].lstrip('_')
    # if the class name starts with underscores, they must
    # be stripped; this is how the mangling mechanism works
    sup=_super(); sup.__thisclass__=cls # trick to avoid __init__ in _super
    setattr(cls,'_%s__super' % strippedname,sup)

    Here is the module safetype.py:

    # safetype.py

    """Deep, **DEEP** magic to remove metaclass conflicts.

    ``safetype`` provides the ``safetype`` metaclass, the mother of conflict-free
    metaclasses. The suggested import syntax for usage in other modules is

    from safetype import safetype as type

    If you override ``__new__`` when you derive from ``safetype``,
    you should do it cooperatively.

    Example:

    >>> from safetype import type


    >>> class M(type):

    .... def __new__(mcl,*args):
    .... print 'creating a class from M'
    .... return super(M,mcl).__new__(mcl,*args)

    >>> class N(type):

    .... def __new__(mcl,*args):
    .... print 'creating a class from N'
    .... return super(N,mcl).__new__(mcl,*args)

    >>> class C:

    .... __metaclass__=M
    creating a class from M

    >>> class D:

    .... __metaclass__=N
    creating a class from N

    >>> class E(C,D):

    .... pass
    creating a class from M
    creating a class from N

    >>> E.__class__ # automagically created

    <class 'safetype.MN'>
    >>> E.__metaclass__ # inherited from C

    <class 'M'>
    """

    import sys,sets,types,__builtin__

    __type__=__builtin__.type
    #the aboriginal 'type'; useful if you rebinds 'type' to 'safetype'

    metadic={} # associates tuple of bases metaclasses to children metaclasses

    class safetype(type):
    """Overrides the ``__new__`` method of the ``type`` metaclass, making the
    generation of classes conflict-proof."""
    # Seventeen lines of DENSE code!
    def __new__(mcl,*args):
    nargs=len(args)
    if nargs==1: # works as __builtin__.type
    return __type__(args[0])
    elif nargs==3: # creates the class using the appropriate metaclass
    n,b,d = args # name, bases and dictionary
    mb=map(__type__,b) # metaclasses of the bases
    meta=generatemetaclass([mcl,]+mb) # recursive
    if mcl is meta: # meta is trivial, dispatch to the default __new__
    return super(safetype,mcl).__new__(mcl,n,b,d)
    elif is_less_specific(mcl,mb): # dispatch to meta.__new__
    return meta.__new__(meta,n,b,d)
    else: # non-trivial metaclass, dispatch to the right __new__
    # (it will take a second round)
    return super(mcl,meta).__new__(meta,n,b,d)
    else:
    raise TypeError('%s() takes 1 or 3 arguments' % mcl.__name__)

    def generatemetaclass(metas):
    """Given a sequence of metaclasses, removes redundances and, if needed,
    creates a new metaclass; returns the metaclass and updates the global
    dictionary.of metaclasses. If the metaclass is already in the dictionary,
    simply retrieves it."""

    metabases=remove_redundant(metas)# metas have the priority
    if metabases in metadic: # already generated metaclass
    return metadic[metabases]
    elif len(metabases)==1: # single metabase
    meta=metabases[0]
    else: # multiple metabases
    metaname=''.join([m.__name__ for m in metabases])
    meta=safetype(metaname,metabases,{})
    return metadic.setdefault(metabases,meta)

    def is_less_specific(c,ls):
    "c is an ancestor of (at least) one class in the list ls."
    for C in ls:
    if issubclass(C,c) and C is not c: return True
    return False

    def remove_redundant(bases):
    """Returns a tuple of non-redundant base classes.
    Given a sequence of base classes, a class is redundant if

    1. it is duplicated;
    2. it is implied by the others, i.e. it is an ancestor of at least one
    of the other classes;
    3. it is ClassType, the metaclass of old style classes.

    For instance, if ``C`` is derived from ``B``, in the
    sequence ``C,B`` the class ``B`` is redundant, since all its features are
    already provided by ``C``. Therefore ``B``
    is removed and ``remove_redundant`` returns the tuple ``(C,)``:

    >>> class B(object): pass

    ...
    >>> class C(B): pass

    ...
    >>> import safetype; safetype.remove_redundant([C,B])

    (<class 'C'>,)
    """
    redundant=sets.Set((types.ClassType,)) # old style metaclass
    ls=list(bases)
    for c in bases:
    if is_less_specific(c,ls) or c in redundant:
    ls.remove(c)
    else: # c is a redundant class to be removed if found
    redundant.add(c)
    return tuple(ls)
    Michele Simionato, Jan 15, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex Nitulescu
    Replies:
    5
    Views:
    1,341
    Alan Silver
    Mar 3, 2005
  2. Guest

    super.super.super how?

    Guest, Feb 19, 2005, in forum: Java
    Replies:
    24
    Views:
    10,762
    Darryl Pierce
    Feb 24, 2005
  3. Richard
    Replies:
    8
    Views:
    586
    Richard
    Feb 7, 2005
  4. Alessandro Bottoni

    Is there a better/simpler logging module?

    Alessandro Bottoni, Aug 8, 2005, in forum: Python
    Replies:
    2
    Views:
    247
    Michael Hoffman
    Aug 8, 2005
  5. tmallen
    Replies:
    19
    Views:
    550
    Miles
    Nov 5, 2008
Loading...

Share This Page