<br><br><div><span class="gmail_quote">On 3/15/07, <b class="gmail_sendername">Greg Ewing</b> <<a href="mailto:greg.ewing@canterbury.ac.nz">greg.ewing@canterbury.ac.nz</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Guido van Rossum wrote:<br>> We could even do this by hacking the default getattr<br>> implementation to skip the instance dict if the name starts and ends<br>> with two underscores.<br><br>But unless I'm mistaken, this behaviour is only
<br>appropriate for *methods*, and you can't tell<br>just from whether the name has double underscores<br>whether it's a method or not.</blockquote><div><br>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.)
<br><br>For instance:<br><br>import types<br><br>class SpecialMethodDescr(object):<br> def __init__(self, func):<br> self.func = func<br> def __get__(self, inst, cls=None):<br> # For backward compatibility, insert inst.__dict__ checks and warns here (and we should get our name passed in.)
<br> return self.func.__get__(inst, cls)<br> def __set__(self, inst, value):<br> # Possibly allow assignment here, by assigning to inst.__dict__, but warn about it not being used.<br> raise AttributeError
<br><br>class SMDType(type):<br> def __new__(cls, name, bases, attrs):<br> for attr in attrs:<br> if (attr.startswith("__") and attr.endswith("__") and<br> isinstance(attrs[attr],
types.FunctionType)):<br> attrs[attr] = SpecialMethodDescr(attrs[attr])<br> return super(SMDType, cls).__new__(cls, name, bases, attrs)<br><br>class smd_object(object):<br> __metaclass__ = SMDType
<br><br>And to see it in action:<br><br>>>> class Old(object):<br>... def __repr__(self):<br>... return "Old.__repr__"<br>...<br>>>> class New(smd_object):<br>... def __repr__(self):<br>
... return "New.__repr__"<br>...<br>>>> o = Old()<br>>>> n = New()<br>>>> def o_repr():<br>... return "o_repr"<br>...<br>>>> o.__dict__['__repr__'] = o_repr
<br>>>> def n_repr():<br>... return "n_repr"<br>...<br>>>> n.__dict__['__repr__'] = n_repr<br>>>> o<br>Old.__repr__<br>>>> n<br>New.__repr__<br>>>> o.__repr__()
<br>'o_repr'<br>>>> n.__repr__()<br>'New.__repr__'<br><br></div></div>-- <br>Thomas Wouters <<a href="mailto:thomas@python.org">thomas@python.org</a>><br><br>Hi! I'm a .signature virus! copy me into your .signature file to help me spread!