[Python-3000] defop ?

Phillip J. Eby pje at telecommunity.com
Thu Nov 23 00:32:38 CET 2006


At 02:06 PM 11/22/2006 -0800, Guido van Rossum wrote:
> > (The 'decorate_class' function applies its argument as a class decorator
> > for the class its caller is invoked from.  This is the same mechanism (and
> > actual code!) that Zope uses to do in-body class decorators like
> > 'implements()'.)  decorate_class raises a SyntaxError if its caller is not
> > being run directly inside a class body.
>
>That's a bizarre use of that exception.

Well, the idea was that a class decorator can only be invoked inside a 
class, so it's a syntax error to invoke it elsewhere.  And, there's little 
chance of confusing the SyntaxError with some error generated by *running* 
the decorator itself, as opposed to merely its positioning.

Anyway, it seemed like a good idea at the time.  :)


>I'm guessing that decorate_class squirrels away some info for later?

It introduces a stealth metaclass to the class frame, that will call the 
decorator.  If there's an existing metaclass in the frame, it invokes it 
first to create the class.  The devil is in the details, of course, and it 
does require that you define any explicit metaclass *before* using any 
class decorators, but this is a documented limitation of the DecoratorTools 
library.


>Everything here seems designed to hide the implementation details,
>which is great for actual use, but kills understanding of the
>mechanism. :-(
>
> > And yes, this uses frame magic, and no, it's not fragile, as it knows the
> > difference between class and non-class frames.
>
>Wow. How can you tell?

Basically, if f_locals contains a '__module__' key that's equal to the 
'__name__' in f_globals, although there are some interesting corner cases 
involving 'exec' -- the details are in the implementation.  The relevant 
function is the 'frameinfo(frame)' function which tells you what "kind" of 
frame you have.


>  Does it work with Jython, IronPython and PyPy?

PyPy should be fine, since it uses the same code objects and 
bytecode.  IIRC, the others emulate enough of the frame protocol that the 
'__module__' and '__name__' checks should be no problem.  However, I have 
not tried it in any of these.  Since this hack requires metaclass support, 
there was no point to attempting it in Jython.  And when the code was 
written, neither IronPython nor PyPy existed yet.


>I still find it fragile somehow -- or at least severely hackish. I
>like the other proposal (where it puts a special attribute on the
>function object which is then found by the type) better, it doesn't
>require sys._getframe().

Sure, there are certainly lots of other ways to implement it!  What I 
showed was just to demonstrate the *possibility*.  If there were defop 
syntax, then of course the compiler could simply generate the appropriate 
bytecode following the MAKE_CLASS operation.  Or MAKE_CLASS could look for 
some data inserted into the source dictionary.

decorate_class() is just what I had handy to answer your question - it 
should not be confused with being the One Obvious Way to do it is.  It's 
just proof of possibility (and practical workability, in that it has been 
long and widely used successfully with at least CPython).

But, there are still other ways.  The compiler could stick 
"__owning_class__" attributes on any function defined in a class, and 
__addmethod__ could defer actually registering the functions until the 
generic function was invoked, thus ensuring that __owning_class__ would be 
set first.

In general, if we're allowed to change the implementation of Python, it's 
easy to find some way to do it.  But you asked for a way to do it in (I 
thought) today's Python, so that's what I gave you.


>I'm assuming that's outside the context of the BinaryTree class --
>since inside it, Binarytree is undefined.

Correct.


>Hm, I think this is the first time in this thread that you meant to
>use 'iter', 'len' etc. as "tokens".

I don't understand what you mean.  They're objects, and so usable as 
tokens.  That's why I've also been saying they can also represent 
"abilities", with defop being a way to unify their use as generic operation 
(e.g. iter()), implementation (i.e. defop iter), and "interface" or ability 
(e.g. 'hasmethod(iter,ob)' or something of that sort).


>I think I'd rather change them a
>bit so that they can be objects that actually understand __addmethod__
>and __hasmethod__.

Okay.  That's an example of the kind of preference I have no way to divine 
ahead of time.  If I knew you preferred function attributes for deferred 
registration, and to make these objects of a special type, I'd have 
proposed it that way.  :)  My assumption was that changing the type of 
Python builtin functions would be considered more "radical" than the idea 
of defop, since it requires changing something, rather than just adding.


> > then there's no need to have
> > actual addmethod/hasmethod functions.  But that's sort of like saying we
> > don't need getattr() any more because we can just use
> > type(ob).__getattribute__() now!  :)
>
>But I think you're really proposing an addmethod builtin that calls an
>__addmethod__ method, right?

Yes, assuming that we can call do this with regular functions too.  That 
is, as long as there's some way to retroactively overload a regular 
function.  Other than that, I'm not worried about the need to retrofit any 
other existing generic function types; their authors will have to change 
them for Py3K anyway.  :)



More information about the Python-3000 mailing list