[Python-3000] __special__ attrs looked up on the type, not instance
Thomas Wouters
thomas at python.org
Thu Mar 15 01:02:18 CET 2007
On 3/15/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
>
> Guido van Rossum wrote:
> > We could even do this by hacking the default getattr
> > implementation to skip the instance dict if the name starts and ends
> > with two underscores.
>
> But unless I'm mistaken, this behaviour is only
> appropriate for *methods*, and you can't tell
> just from whether the name has double underscores
> whether it's a method or not.
We can make __*__ methods be a different kind of method (by making the
metaclass wrap them up in a different kind of descriptor, one with __set__
set. Python treats descriptors with a __set__ slightly different than those
without __set__: it bypasses __dict__ entirely, for new-style classes. This
trick doesn't work for classic classes.)
For instance:
import types
class SpecialMethodDescr(object):
def __init__(self, func):
self.func = func
def __get__(self, inst, cls=None):
# For backward compatibility, insert inst.__dict__ checks and warns
here (and we should get our name passed in.)
return self.func.__get__(inst, cls)
def __set__(self, inst, value):
# Possibly allow assignment here, by assigning to inst.__dict__, but
warn about it not being used.
raise AttributeError
class SMDType(type):
def __new__(cls, name, bases, attrs):
for attr in attrs:
if (attr.startswith("__") and attr.endswith("__") and
isinstance(attrs[attr], types.FunctionType)):
attrs[attr] = SpecialMethodDescr(attrs[attr])
return super(SMDType, cls).__new__(cls, name, bases, attrs)
class smd_object(object):
__metaclass__ = SMDType
And to see it in action:
>>> class Old(object):
... def __repr__(self):
... return "Old.__repr__"
...
>>> class New(smd_object):
... def __repr__(self):
... return "New.__repr__"
...
>>> o = Old()
>>> n = New()
>>> def o_repr():
... return "o_repr"
...
>>> o.__dict__['__repr__'] = o_repr
>>> def n_repr():
... return "n_repr"
...
>>> n.__dict__['__repr__'] = n_repr
>>> o
Old.__repr__
>>> n
New.__repr__
>>> o.__repr__()
'o_repr'
>>> n.__repr__()
'New.__repr__'
--
Thomas Wouters <thomas at python.org>
Hi! I'm a .signature virus! copy me into your .signature file to help me
spread!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/python-3000/attachments/20070315/f2cb887e/attachment.htm
More information about the Python-3000
mailing list