On Sun, Mar 9, 2008 at 5:54 AM, Greg Ewing <[EMAIL PROTECTED]> wrote:
> Anthony Tolle wrote:
>  > As for a more concrete example, imagine the wrapper using the inspect
>  > module to gather some information about the stack frame and passing it
>  > along to selected methods.
>
>  That's still not very concrete. It doesn't demonstrate
>  why you would want to find out that particular piece of
>  information.
>

Ok, I have something that I hope is concrete enough.  It is (yet
another) version of autosuper that I put together for Python 2.5,
since it doesn't have the magic version of super() from 3.0.  Rather
than write a new super function, I wanted to write something that
would work by inserting the correct value of super into the argument
list.  In fact, this script is why I brought up the whole discussion.

Now, while the point of the script itself is moot in version 3.0, it
is still a concrete example of what I've been discussing.  When I
realized that the check for a static method wouldn't work in 3.0, I
began to wonder if anyone else had run across the same problem, or if
they even cared.

Here's the script, which includes some assertions to test its behavior:

------------------------------------------------------------

class autosuper_method(object):
    def __init__(self, desc, cls=None):
        self.desc = desc
        self.cls = cls

    def __get__(self, obj, type=None):
        return autosuper_callable(self.desc,
                                  self.cls,
                                  self.desc.__get__(obj, type))

class autosuper_callable(autosuper_method):
    def __init__(self, desc, cls, callable):
        self.desc = desc
        self.cls = cls
        self.callable = callable

    def __call__(self, *args, **kwargs):
        if self.cls is None:
            raise TypeError('must inherit from autosuper')
        try:
            obj = self.callable.im_self
        except AttributeError:
            raise TypeError('autosuper used with static method')
        if obj is None:
            obj = args[0]
            return self.callable.__call__(obj,
                                          super(self.cls, obj),
                                          *args[1:],
                                          **kwargs)
        return self.callable.__call__(super(self.cls, obj),
                                      *args,
                                      **kwargs)

class autosuper_meta(type):
    def __init__(cls, name, bases, clsdict):
        # fix up all autosuper_method instances in class
        for attr in clsdict.keys():
            value = clsdict[attr]
            if isinstance(value, autosuper_method):
                type.__setattr__(cls,
                                 attr,
                                 autosuper_method(value.desc, cls))

    def __setattr__(cls, attr, value):
        # catch assignment after class definition
        if isinstance(value, autosuper_method):
            value = autosuper_method(value.desc, cls)
        type.__setattr__(cls, attr, value)

class autosuper(object):
    __metaclass__ = autosuper_meta

if __name__ == '__main__':
    class A(autosuper):
        @classmethod
        def cm(cls):
            return 'A(%s)' % cls.name

        def im(self):
            return 'A(%s)' % self.name

    # Demo - standard use
    class B(A):
        @autosuper_method
        @classmethod
        def cm(cls, super):
            return 'B' + super.cm()

        @autosuper_method
        def im(self, super):
            return 'B' + super.im()

    # Demo - reference super in inner function
    class C(A):
        @autosuper_method
        @classmethod
        def cm(cls, super):
            def inner():
                return 'C' + super.cm()
            return inner()

        @autosuper_method
        def im(self, super):
            def inner():
                return 'C' + super.im()
            return inner()

    # Demo - define function before class definition
    @autosuper_method
    @classmethod
    def D_cm(cls, super):
        return 'D' + super.cm()

    @autosuper_method
    def D_im(self, super):
        return 'D' + super.im()

    class D(B, C):
        name = 'D'
        def __init__(self, name):
            self.name = name
        cm = D_cm
        im = D_im

    # Demo - define functions after class definition
    class E(B, C):
        name = 'E'
        def __init__(self, name):
            self.name = name

    @autosuper_method
    @classmethod
    def E_cm(cls, super):
        return 'E' + super.cm()

    @autosuper_method
    def E_im(self, super):
        return 'E' + super.im()

    E.cm = E_cm
    E.im = E_im

    # Test D
    d = D('d')
    assert d.cm() == 'DBCA(D)'  # class method, instance binding
    assert D.cm() == 'DBCA(D)'  # class method, class binding
    assert d.im() == 'DBCA(d)'  # instance method, instance binding
    assert D.im(d) == 'DBCA(d)' # instance method, class binding

    # Test E
    e = E('e')
    assert e.cm() == 'EBCA(E)'  # class method, instance binding
    assert E.cm() == 'EBCA(E)'  # class method, class binding
    assert e.im() == 'EBCA(e)'  # instance method, instance binding
    assert E.im(e) == 'EBCA(e)' # instance method, class binding

    # Give E cm and im from D
    E.cm = D.cm
    E.im = D.im
    assert e.cm() == 'DBCA(E)'  # class method, instance binding
    assert E.cm() == 'DBCA(E)'  # class method, class binding
    assert e.im() == 'DBCA(e)'  # instance method, instance binding
    assert E.im(e) == 'DBCA(e)' # instance method, class binding

------------------------------------------------------------

I can imagine the next question: If this version of autosuper doesn't
work for static methods (it doesn't make sense that it would, since
super only works when bound), then why would I care if it couldn't
check for static methods?  Why not just assume it will be used for
class methods and instance methods, and adjust the code accordingly?

Well, that was my question from the beginning: When writing a wrapper
like this, would anyone care if it could no longer distinguish between
static methods and unbound methods, in Python 3.0?

So far, it sounds like the answer is 'no', which is fine with me.  I
just thought I'd bring it to everyone's attention.
_______________________________________________
Python-3000 mailing list
Python-3000@python.org
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe: 
http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com

Reply via email to