[Python-Dev] method decorators (PEP 318) (original) (raw)

Robert Mollitor mollitor at earthlink.net
Fri Mar 26 14:55:12 EST 2004


On Friday, March 26, 2004, at 12:56 PM, Phillip J. Eby wrote:

At the same time, I realize Python also generally prefers to have different syntax for different use cases. But, how different are these use cases, really? They're all changing the function in some way.

Actually, not really, and that is the problem as I see it. (I should preface the following with "I'm not an expert and may have things completely wrong".)

Consider

class C:
    def m(self,a,b): pass
    m.hat =  "top"
    m.shoes = "wingtip"

    def cm(cls,a,b): pass
    cm.hat = "baseball"
    cm = classmethod(cm)
    cm.shoes = "sneakers"

Assuming this even worked (which it doesn't because classmethod has read-only attributes), there are two objects named "cm" in this picture. The latter one wraps the earlier one. This means that the 'hat' and 'shoes' attributes would not be "on" the same object. Now this might be ok if you access the attribute through the classmethod instance because it could redirect the 'getattr'. However "C.cm" != "C.dict['cm']". In fact, as far as I can tell, due to the way the binding occurs, once you do the binding ("C.cm"), there is no way to get back to the classmethod instance (the object actually stored in C's dict). To keep things sane, we probably want all function "attributes" to be on the true function object anyway. The wrapper object might have its own attributes which control the binding operation, but those are separate things.

So the main issue, I think, is that syntactically we want "transformers" like classmethod and staticmethod (and potentially others) to be front-and-center in the main function definition line, but we want them to be "applied" last. For this reason, we actually do need a new "decoration" syntax (wherever it ends up lexically) which to set up any function attributes (metadata like docstrings) on the function object itself. This is because the 'old way' of "cm.shoes = 'sneakers'" won't work (because it won't be before the wrapping), though perhaps it could be made to work if the classmethod redirects the 'setattr' to the contained function object.

There is a secondary issue of how to handle chained transformers.
classmethod and staticmethod are mutually exclusive, but in general transformers need not be. Let's say there was a 'synchronized' transformer that we want for class methods, too. Not only would we want "synchronized(classmethod(f))" to work, but we would probably want "classmethod(synchronized(f))" to work identically. This is not easy unless either the implementation of each was aware of the other (or at least the possibility of the other), or all transformers must be written to a tight specification. However, I admit that I don't fully understand the whole descriptor thing yet.

Robert Mollitor



More information about the Python-Dev mailing list