Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > super. could there be a simpler super?

Reply
Thread Tools

super. could there be a simpler super?

 
 
Kerim Borchaev
Guest
Posts: n/a
 
      01-15-2004
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 (E-Mail Removed)



 
Reply With Quote
 
 
 
 
Kristian Ovaska
Guest
Posts: n/a
 
      01-15-2004
Kerim Borchaev <(E-Mail Removed)>:
> 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/
 
Reply With Quote
 
 
 
 
Gonšalo Rodrigues
Guest
Posts: n/a
 
      01-15-2004
On Thu, 15 Jan 2004 11:50:57 +0300, Kerim Borchaev <(E-Mail Removed)>
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

 
Reply With Quote
 
Gerrit Holl
Guest
Posts: n/a
 
      01-15-2004
Kristian Ovaska wrote:
> Kerim Borchaev <(E-Mail Removed)>:
> > 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/c.../pep-xxxx.html
Asperger's Syndrome - a personal approach:
http://people.nl.linux.org/~gerrit/english/

 
Reply With Quote
 
Michele Simionato
Guest
Posts: n/a
 
      01-15-2004
Kerim Borchaev <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> 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 (E-Mail Removed)


``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)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is there a better/simpler way to filter blank lines? tmallen Python 19 11-05-2008 11:07 PM
Is there a simpler way to do this? Julian Leviston Ruby 12 08-27-2005 11:16 PM
Is there a better/simpler logging module? Alessandro Bottoni Python 2 08-08-2005 06:01 PM
Is there a simpler way (trick) to create composite controls ? Alex Nitulescu ASP .Net 5 03-03-2005 11:17 AM
Hey Nigel dude could it get any simpler? Richard HTML 8 02-07-2005 05:42 PM



Advertisments