super, decorators and gettattribute

Richard Szopa ryszard.szopa at gmail.com
Mon Jan 14 17:47:36 EST 2008


On Jan 14, 1:53 pm, Michele Simionato <michele.simion... at gmail.com>
wrote:

> I really need to publish this one day or another, since these
> questions
> about super keeps coming out:
>
> http://www.phyast.pitt.edu/~micheles/python/super.html

Thanks, Michele! Your essay was enlightening [2]. Specially if you
take in account super's documentation is slightly outdated :).

I also read Raymond Hettinger's article about descriptors (which you
mention, but don't link to!) and decided to use them to reimplement
methods that always call their superclass [1] method of the same name.
Could you tell me what are the pros and cons of the two approaches
(i.e. writing a decorator function and a decorator descriptor class)?
The former gives slightly shorter code, while the second gives access
to the original function and I somehow feel it is more... classy :)
[code follows]

Cheers,

    -- Richard

[1] By which I mean the first class in their MRO.
[2] I also found some other papers of yours about the "not for the
faint of heart" corners of Python: MRO, metaclasses, class
memoization, etc. and they were most enjoyable and interesting.

def callingprevious1(fun):
    """Decorator to call a superclass' fun first. Decorator function
    approach.

    >>> class parent(object):
    ...     def foo(self):
    ...         print "I am foo of parent"
    ...
    >>> class child(parent):
    ...     @callingprevious1
    ...     def foo(self):
    ...         print "I am foo of child"
    ...
    >>> x = child()
    >>> x.foo()
    I am foo of parent
    I am foo of child
    >>> child.foo(x)
    I am foo of parent
    I am foo of child
    """

    name = fun.__name__
    def decorated(self, *args, **kwargs):
        try:
            super_object = super(self.__class__, self)
            getattr(super_object, name)(*args, **kwargs)
        except AttributeError:
            pass # if parent doesn't implement fun, we don't care
                 # about it
        return fun(self, *args, **kwargs) # hopefully None

    decorated.__name__ = name
    return decorated

class callingprevious(object):
    """
    Decorator making the defined method call the method of the first
    superclass in mro at the beginning. Descriptor approach.

    >>> class parent(object):
    ...     def foo(self):
    ...         print "I am foo of parent"
    ...
    >>> class child(parent):
    ...     @callingprevious
    ...     def foo(self):
    ...         print "I am foo of child"
    ...
    >>> x = child()
    >>> x.foo()
    I am foo of parent
    I am foo of child
    >>> child.foo(x)
    I am foo of parent
    I am foo of child
    """

    def __init__(self, initval):
        self.name = initval.__name__
        self.__combine_methods(initval)

    def __combine_methods(self, val):
        self.val = val
        def with_parent(obj, *args, **kwargs):
            try:
                parent_method = getattr(super(type(obj), obj),
self.val.__name__)
            except AttributeError:
                pass
            else:
                parent_method(*args, **kwargs)
            return self.val(obj, *args, **kwargs)
        with_parent.__name__ = self.val.__name__
        self.to_return = with_parent

    def __get__(self, obj, objtype):
        from types import MethodType

        # btw, is it anyhow better than just returning the function?
        return MethodType(self.to_return, obj, objtype)

    def __set__(self, obj, val):
        self.__combine_methods(val)



More information about the Python-list mailing list