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
[email protected]
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe:
http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com